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?
Asked Answered
T

6

6

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).

Tuckerbag answered 28/3, 2011 at 18:25 Comment(0)
T
0

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.

Tuckerbag answered 31/3, 2011 at 0:12 Comment(0)
H
8

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.

Helle answered 8/9, 2018 at 5:51 Comment(0)
C
1

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.

Cherokee answered 28/3, 2011 at 18:34 Comment(1)
Yup, I'm aware that attr_accessor is a Ruby method, and I know that attr_accessible is to specify which attributes permit mass assignment. I think you're right about Rails 3 - given that validations now happen outside of ActiveRecord it would likely be easier to do this.Tuckerbag
G
0

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.

Giraldo answered 28/3, 2011 at 18:37 Comment(1)
Yeah - I do mean virtual, I guess they're all the same to me. I could definitely handle the conversion and even validation by some form of metaprogramming, but wanted to know if there was built-in stuff that I was missing.Tuckerbag
T
0

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.

Tuckerbag answered 31/3, 2011 at 0:12 Comment(0)
A
0

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
Adolfo answered 8/1, 2012 at 4:30 Comment(2)
This doesn't address the question at all, which is related to automatically having rails typecast the attribute to the desired type.Tuckerbag
then check this answer... https://mcmap.net/q/1782108/-type-casting-values-during-an-attr_accessor... he address that writting his own attr_accesor.. since ruby attr_accessor its just for setting values... its doesnt care about variable types...Adolfo
B
0

Add the following to your model:

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

reference: Rails ActiveRecord::MultiparameterAssignmentErrors

Baeda answered 30/12, 2012 at 21:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.