Rails Mass Assignment on Integer Value From a Form - ruby-on-rails

All values coming from a web form are string. I have a class named Announcement which has a field kind and its data type is integer. On the model class I define an enum
enum kind: {
event: 1,
feature: 2
}
About mass assignment I have done it, no problem in general. The problem is when I'm doing this it will complain about '1' is not a valid kind because it's a string not an integer.
announcement=Announcement.new(announcement_params)
Is there any solution for this problem except manually set the value for the field?
Thank you

The answer just come to my mind, this is what i do to solve the problem
kind=params[:announcement][:kind].to_i
params[:announcement].delete(:kind)
params[:announcement].merge(kind: kind)
Get the kind param and convert it to an integer
Remove the kind which is a string from the params
Merge the new kind to the params
And the last is white listing parameters for mass assignment
Thank you #uzaif

You can redefine the setter for the kind attribute in your Announcement model, like this:
# app/models/announcement.rb
def kind=(value)
super(value.to_i)
# or
# super(Integer(value))
end
This converts the given value to integer first and then calls the original method defined by the enum. Note however, that to_i will convert anything, even non-numbers or nils - these will be converted to 0. So I'd advise to either never use 0 among your defined enum values or to use the Integer(value) form, which will raise an exception on non-numbers or nils.
The setter allows mass assignment again:
Announcement.new(kind: '1') # should be OK

Related

How to write validation for enum in rails

I have an enum in one of my model in my api
enum pay_method: {
cash: 0,
card: 1
}
I want to have validation for this enum but i can not do that . I wrote a validation in my model for that but it did not take any effect
A validation for enum is not going to work, because Rails does not even allow to assign an enum variable with a wrong value. You will get an error before a validation. There is a good discussion of this behaviour here https://github.com/rails/rails/issues/13971
rails enum functionality throws an error if the value submitted does not correspond to one of the keys or values of the hash. in this case it does not correspond to the key because the value you are submitting is a string so until here you are correct.
the error still appear because enums are set before the validation process. this could help you understand
#shippimg = Shippig.first
#shipping.status = 99
ArgumentError: '99' is not a valid status
rails developers say that programmers are the ones responsible taking care of what values they use assingning to enum attributes
i have made a gem for validating enums inclusion. this at least stops your server from crashing https://github.com/CristiRazvi/enum_attributes_validation

How to update value in angular ui typeahead directive if no matching option is found

I've an array of objects containing title and salary which is used in typeahead directive.
I display department name and get entire object as value.
If none of the options match, I want user entered string to be converted to object still. Is there any way to update that?
This answer is pretty late, but I would just use ng-blur (to trap the end of the users input) along with a variable bound to typeahead-no-results. Then test if the variable is true in the method bound to ng-blur, and, if so, make an object out of the String supplied by the user and push it to your data source. Simple example found here.

rails 3: how build a string catenating all values of a single field, without iteration?

If my table Foo contains a field :code
If Foo has 3 records with :code = "AAAA" "BBBB" and "CCCC"
I'm trying to build a string
"AAAA_BBBB_CCCC"
(I'm passing a set of field values to an external program via URL and that's how it expects multiple values to be passed to it)
Doing
Foo.select("code").join("_")
doesn't work because the items joined are not the actual value of "code", but some sort of hash or association which has an attribute called "code"
maybe
Foo.select("code").map(&:code).join("_")
but this isn't properly without iteration ...
I thkink you could resolve this with composed_of method instead of simple concatenation
http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html
http://apidock.com/rails/ActiveRecord/Aggregations/ClassMethods/composed_of

validation before attribute setters can type cast

I have an object with an attribute called value which is of type big decimal. In the class definition i have validates_numericality_of.
However if i:
a.value = 'fire'
'fire' ends up getting typecast to the correct type before the validation fires so:
a.valid? => true
How do get the validation to fire before the typecast?
Thanks
Dan
From ActiveRecord::Base docs:
Sometimes you want to be able to read
the raw attribute data without having
the column-determined typecast run its
course first. That can be done by
using the <attribute>_before_type_cast
accessors that all attributes have.
For example, if your Account model has
a balance attribute, you can call
account.balance_before_type_cast or
account.id_before_type_cast.
This is especially useful in
validation situations where the user
might supply a string for an integer
field and you want to display the
original string back in an error
message. Accessing the attribute
normally would typecast the string to
0, which isn’t what you want.
A new gem has been created to help validate types in rails.
An explanatory blog post exists to answer more of the "why" it was created in the first place.
With this library your code could be:
class SomeObject < ActiveRecord::Base
validates_type :value, :big_decimal
end
This will throw an exception when anything except a float is assigned to value instead of quietly casting the value to a BigDecimal and saving it.

Ascii to Int function in Groovy

I'm trying to pass the value "1" into a Grails tag. However, it turns out to be an integer value of 49 - the ascii value for "1". How do I convert this to the proper value in Groovy?
Actually, there's a "toInteger()" function on a String.
To add to Jack BeNimble's comment, if you are using 1.2 (release of which is imminent), you also have null-safe converters to int (i.e. params.int('value'), which will do
From Release Notes.
Convenient, null safe converters in params and tag attributes
New convenience methods have been added to the params object and tag attrs objects that allow the easy, exception safe and null safe conversion of parameters to common types:
def total = params.int('total')
There are methods for all the common base types such as int#, #long#, #boolean and so on. There is a special converter called list that always returns a list for cases when dealing with one or many parameters of the same name:
def names = params.list('names')

Resources