Rails: Using form fields that are unassociated with a model in validations

11,472

Solution 1

Don't let params sneak up to the model. There's no point of having a controller in that case. Instead, checkout this episode from Railscasts that talks about virtual attributes that do not go into the database but can still be used for validations.

You don't need a corresponding model attribute for the virtual attributes. Define attributes local to the class such as @no_fairways that hold the state.

class ScoreCard < ActiveRecord::Base
  # define attributes and accessors for both fields
  attr_accessor :no_fairways, :no_girs

  ..
end

Now inside you form, you could just write:

<% form_for @scorecard %>
  <%= f.check_box :no_fairways %>
<% end %>

Solution 2

Found the solution, thanks for the lingo though, "virtual attribute" helped with the google searchin.

The cleanliest way to accomplish this is to create attributes that are not part of the database but still part of the model. In my case I put this into the model:

attr_accessor :no_fairways
attr_accessor :no_girs

That easy! Now @scorecard.no_fairways and @scorecard.no_girs act just like any other attribute but aren't part of the database.

Share:
11,472
Jay
Author by

Jay

Updated on July 18, 2022

Comments

  • Jay
    Jay almost 2 years

    In a Ruby on Rails application I am trying to use information from fields that are not associated with the model in validation.

    Here is part of the model as an example (the whole model has gotten kinda big):

    class Scorecard < ActiveRecord::Base
      belongs_to :course
      belongs_to :user
    
      validate :attributes_consistency
    
      def attributes_consistency
        # Executed for all scorecards.  Checks if the user completed the hole attributes correctly
        if ( params[:no_fairways] and any_fairways? and !only_nine? ) or ( params[:no_fairways] and !any_h1_to_h9_score_blank and any_h1_to_h9_fairway? and only_nine? ) or ( params[:no_fairways] and !any_h10_to_h18_score_blank and any_h10_to_h18_fairway? and only_nine? )
          errors.add_to_base("You inidicated that you missed all the fairways, but you also marked one or more fairways in the scorecard.  Either uncheck the fairways mistakenly marked or uncheck the 'No fairways' checkbox.")
        end
        if ( params[:no_girs] and any_girs? and !only_nine? ) or ( params[:no_girs] and !any_h1_to_h9_score_blank and any_h1_to_h9_gir? and only_nine? ) or ( params[:no_girs] and !any_h10_to_h18_score_blank and any_h10_to_h18_gir? and only_nine? )
          errors.add_to_base("You inidicated that you missed all the greens, but you also marked one or more greens in the scorecard.  Either uncheck the marked greens on the scorecard or uncheck the 'No GIRs' checkbox.")
        end
      end # attributes_consistency
    
    
      def any_h1_to_h9_score_blank?
        h1_score.blank? or h2_score.blank? or h3_score.blank? or h4_score.blank? or h5_score.blank? or h6_score.blank? or h7_score.blank? or h8_score.blank? or h9_score.blank?
      end
      def any_h10_to_h18_score_blank?
        h10_score.blank? or h11_score.blank? or h12_score.blank? or h13_score.blank? or h14_score.blank? or h15_score.blank? or h16_score.blank? or h17_score.blank? or h18_score.blank?
      end
    
      def any_h1_to_h9_fairway?
        h1_fairway? or h2_fairway? or h3_fairway? or h4_fairway? or h5_fairway? or h6_fairway? or h7_fairway? or h8_fairway? or h9_fairway?
      end
      def any_h10_to_h18_fairway?
        h10_fairway? or h11_fairway? or h12_fairway? or h13_fairway? or h14_fairway? or h15_fairway? or h16_fairway? or h17_fairway? or h18_fairway?
      end
    
      def any_h1_to_h9_gir?
        h1_gir? or h2_gir? or h3_gir? or h4_gir? or h5_gir? or h6_gir? or h7_gir? or h8_gir? or h9_gir?
      end
      def any_h10_to_h18_gir?
        h10_gir? or h11_gir? or h12_gir? or h13_gir? or h14_gir? or h15_gir? or h16_gir? or h17_gir? or h18_gir?
      end
    

    So how can I access params from the model?

  • Jay
    Jay almost 14 years
    This would be a great solution but could you give an example of how I might implement this? In that particular Railscast the "virtual attributes" are really methods that manipulate real attributes. I have no attributes that no_fairways or no_girs can be associated with.
  • Chance
    Chance almost 14 years
    @James - the virtual attribute doesn't have to be associated with any database attribute. You could define instance attributes that will work just as well. Updated answer.
  • Scarlet
    Scarlet about 6 years
    Note that attr associated with checkbox will not have trythy or falsy value. By default check_box generates markup that result in "0" string when unchecked and "1" when checked. Even "0".present? is truthy.