1

I've got a model, Photo, that has two options, is_photo or is_art, each with their own separate fields.

But, when one option is chosen I want the other option's fields to be reset into blank strings.

This is what I have:

photo.rb

before_save :reset_photo_options
before_save :reset_art_options

def reset_photo_options
  if self.is_art == 1
    self.resolution = ""
    self.camera = ""
  end
end

def reset_art_options
  if self.is_photo == 1
    self.tool = ""
    self.medium = ""
  end
end

However, if I fill out the is_photo fields and then change to is_art and fill those out all of the fields are saved.

How can I successfully reset the other option's fields?

1
  • There may be some other interactions we don't have visibility into; setting them manually. Make sure the compares are actually firing. If is_art and is_photo are actual DB fields I'd revisit that choice (maybe even STI, which is fine for simple usecases). Commented Feb 1, 2018 at 16:40

2 Answers 2

1

When dealing with mutually exclusive options like this, I always create a single field that has the type. With "enums" you can do something like this:

class Photo
  enum photo_style: [ :art, :photo ]
end

This gives you the ability to use similar methods:

photo.art?

that you would use with straight up booleans.

You can also use them in queries and such:

Photo.where(photo_style: :photo)

For your specific question, you can then roll the logic into a single callback:

before_save :reset_options

def reset_options
  if art?
    # do something
  elsif photo?
    # do something else
  end
end

More here:

http://api.rubyonrails.org/classes/ActiveRecord/Enum.html

Sign up to request clarification or add additional context in comments.

Comments

0

If these are proper boolean columns, at least as far as ActiveRecord is concerned, then you should be able to do this by using the ? method variant that returns a strict true or false value:

def reset_photo_options
  return unless self.is_art?

  self.resolution = nil
  self.camera = nil
end

def reset_art_options
  return unless self.is_photo?

  self.tool = nil
  self.medium = nil
end

Setting as nil is usually better than as empty string since a NULL column is a clear communicator that the field is not relevant and not set. Empty string could indicate missing data or no user input captured.

A further refactoring of this is to describe which fields go with what type:

SPECIFIC_FIELDS = {
  art: [
    :resolution,
    :camera
  ],
  photo: [
    :tool,
    :medium
  ]
}

def mask_off_irrelvant_options
  SPECIFIC_FIELDS.each do |category, fields|
    next unless (self.send(:"is_#{category}?"))

    fields.each do |name|
      self[name] = nil
    end
  end
end

This presumes things can be art and photo at the same time. If that's not the case then you don't need a series of independent booleans, you need one category field.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.