In Rails, is there a way to specify a TYPE you'd like an attr_accessor to be, and validate it using built-in Rails validation?

StackOverflow https://stackoverflow.com/questions/8775391

Question

I've never been able to find a nice way to do this, so I thought I'd ask.

For example, in an ActiveRecord model, database backed attributes are automatically type-converted to the appropriate database-backed types. If I have a Category model, and it has a couple of attributes, say name and category_id, if I go like this:

Category.new(params[:category])

Rails knows that name is a String and category_id is an Integer.

Let's say I have several transient/synthetic attributes that I want to validate, and they have specific types. I want to submit them from a form, and I'd like them to be automatically converted to either a String or an Integer or a Date (for example) based on how they're defined.

If I was to declare something in a Rails model like:

attr_accessor :some_number_variable
attr_accessor :some_date

Is there a built-in way to tell Rails "I'd like you to cast the former to an Integer and the latter to a Date, when I go Category.new(params[:category])" so long as params[:category][:some_number_variable] and params[:category][:some_date] are part of the data submitted to the controller (I realize the Date example might be a bit trickier given the many date formats out there).

Was it helpful?

Solution 4

Neither of the replies quite answer the question. I believe the correct answer to the questions is simply "No". The replies both address potential workarounds to the fact that the answer to the question is "No", and both are valid comments / ideas.

OTHER TIPS

As of Rails 5, there is the Attribute API which you can use like this:

class SomeModel < ActiveRecord::Base
  attribute :a_checkbox_name, :boolean, default: false
end

You can set defaults, and define your own types, among other nice things. Then you can validate these attributes (virtual or not) like any other DB backed one.

attr_accesor just creates reader/writer methods, and it comes from Ruby, not Rails. The Rails method that I believe often gets confused is attr_accessible which serves a different purpose. If you want to cast when the attribute is read, you can just override the reader.

attr_accessor :some_number_variable

def some_number_variable
  @some_number_variable.to_i
end

This will at least give you the writer for free. This is the best solution I know for what (I think) you are describing.

EDIT: As far as validation is concerned, I believe that if you are using Rails 3, it will be much easier for you to perform validation on these sort of attributes (I haven't done it so I can't say for sure). Now that validations aren't tied directly into ActiveRecord, I'd believe it possible.

I assume by "transient/synthetic" attribute you mean a virtual attribute?

If so, there is no built in Rails function that will do this that I can think of offhand, but one solution would be to just write a module for those attributes and include it in the model. Or if it had to be dynamic, you could call the attribute something like :some_variable_integer and then handle those dynamic attributes with method_missing, read the method name, and convert it to the type required.

In my opinion, those are a little messy, so validations in the model are really your best bet if what you're looking to do can support them.

use before_create..

class Category
  attr_accessor :some_number_variable, :some_date
  before_create :validate

 private

   def validate
     return unless !!params[:category]
     #do variable casting here
   end
end

Add the following to your model:

columns_hash["birth_date"] = ActiveRecord::ConnectionAdapters::Column.new("birth_date", nil, "date")

reference: Rails ActiveRecord::MultiparameterAssignmentErrors

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top