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?
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).
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.
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.
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
精彩评论