Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

Need help troubleshooting a custom validator for a serialize array field

How do I validate a serialize Array field in a Rails 4 app (Postgres db)? I have a Member model, which has a "goal" field, a serialized array. The form field is presented as a series of check-boxes where a member can identify fitness goal(s). A member can have multiple goals, but must have at least one goal. My understanding is Rails does not have a built in validation for a serialize array field. So, I'm trying to write a custom validator, but having trouble getting it to work properly.

This is my objective: I want to see the following behaviors in my application: If a member selects at least one goal then validation should pass and the record can be saved to the db. If a member fails to declare any goals then validation should fail and the record is not saved.

Here's relevant code from my member.rb (model) file:

serialize :goal, Array
GOALS = %w[ "Lose Fat", "Gain Muscle", "Get Toned", "Get Shredded", "Get Hulky", "Improve Balance", "Enhance Flexibility", "Maintain Current Weight" ]
validate :goal_check

 protected
   def goal_check
     goal.each do |g|
       errors.add(:goal, "#{g} is invalid; you must check at least one goal") unless GOALS.include? g
     end
   end 

My custom validator is not working as desired. It prevents a member from being saved even when he/she checks at least one goal! Where did I go wrong in my "goal_check" method? How do I write a custom validator that will accomplish my objective? Thank you!

1 Answer

Seth Reece
Seth Reece
32,867 Points

Does GOALS.include?(g) work?

Seth, When I run the code, my custom validator blocks a member from being saved even when he selects a goal in the array. It appears to ignore the checked goal, so I suspect there is a problem somewhere in my include code. To troubleshoot, I ran Launchy and see that a goal was clearly checked. Nevertheless, the validator prevents the record from being saved.

Seth Reece
Seth Reece
32,867 Points

The format for using include is: something.include?(variable) or something.include?("string").

You have GOALS.include? g

I'm not sure how I need to change my code to fix the issue. Any suggestions for how I rework my existing code?

Seth Reece
Seth Reece
32,867 Points

Yes, in your goal.each iteration, change GOALS.include? g to GOALS.include?(g).

e.g.

serialize :goal, Array
GOALS = %w[ "Lose Fat", "Gain Muscle", "Get Toned", "Get Shredded", "Get Hulky", "Improve Balance", "Enhance Flexibility", "Maintain Current Weight" ]
validate :goal_check

 protected
   def goal_check
     goal.each do |g|
       errors.add(:goal, "#{g} is invalid; you must check at least one goal") unless GOALS.include?(g)
     end
   end 

I changed the syntax as you recommended; unfortunately no luck. The custom validator is still not working correctly. As before, it prevents both scenarios: (1) a member without a goal from being saved as well as a (2) a member who correctly selects a goal in the Array field. Hmmm? Any other ideas I can try?

Seth Reece
Seth Reece
32,867 Points

Ahh missed this part. Your GOALS array is declared as GOALS = %w["foo", "bar"]. the %w syntax would be %w(foo bar) so try removing the %w, or removing all quotes, commas, change the square brackets to ().

Seth - no luck getting this validator to work. I changed the syntax in the multiple ways you suggested, but it's still not validating correctly. Still can't save a member who correctly states a fitness goal. The validator does not appear to be able to distinguish when a goal as been checked (or not). This has me stumped but really curious now. I can't see anything obviously wrong. Other than this validation problem, the code works as expected ... no problems. Why won't this work correctly? I appreciate you help, Seth!

Seth Reece
Seth Reece
32,867 Points

Hmm.. I think you might need validates instead of validate below you GOALS array.

Changing "validate" to "validates" throws an "ArgumentError: You need to supply at least one validation." Something seems amiss with my custom validator. I need to do some more research into how to validate serialized attributes. During my earlier research I found a gem for this exact purpose -- validates_serialized -- but since I'm writing the application to learn the Ruby/Rails, I plan to continue my efforts to get my custom validator to work. It may be something really simple but it eludes me for now. Not bad though, I'm learning a LOT of GOOD THINGS writing this application!