When a controller receives the params of a checked checkbox it comes back as "on" if the box was checked. Now in my case I'm trying to store that value as a boolean, which is typically what you want to with values from checkboxes. My question is, does rails have a way to automatically convert "on" (or even exists) to true/false or do I need to do the following?
value = params[my_checkbox] && params[my_checkbox] == "on" ? true : false
You can just use:
value = !params[:my_checkbox].nil?
as the checkbox would not return any value if not checked (implied by this forum)
The best way of doing this is to create a custom setter for the field in the database, something like this:
class Person < ActiveRecord::Base
def active=(value)
value = value == 'on' ? true : false
super(value)
end
end
That way you don't have to worry about it in the controller and it's the model that knows what value it is supposed to be. When you go to the view rails automatically checks a checkbox from a boolean field. Just in case that didn't work you could also define your own getter.
This can be then used for example in conjunction with store accessor something like this:
class Person < ActiveRecord::Base
validates :active, inclusion: {in: [true, false]}
validates :remember_password, inclusion: {in: [true, false]}
store :settings,
accessors: [:active, :remember_password],
coder: JSON
def active=(value)
value = value == 'on' ? true : false
super(value)
end
def remember_password=(value)
value = value == 'on' ? true : false
super(value)
end
end
Note that the setting field in the database has to be text so you can put more stuff in it.
Related
we use checkbox to submit a boolean data in a form.
In rails, when submit the form, a string with "1" or "0" will be submitted to the controller.
In phoenix, when submit the form, a string with "true" or "false" will be submitted to the controller.
It's fine if we directly create object in the database. Either of value will be store as boolean correctly.
But if we need to use the boolean value in our logic, what's the best way to do it?
Convert to boolean:
# Ruby code
def create
admin = ActiveModel::Type::Boolean.new.cast(param[:admin])
if admin
....
end
end
Directly use as string:
# Elixir code
def create(conn, params) do
case params[:admin] do
"true" -> do something
_ -> do others
end
end
Other better ways?
String.to_existing_atom/1 is your friend.
Both true and false are atoms, namely a syntactic sugar for :true and :false. That is because in erlang they are atoms.
:true == true
#⇒ true
:false == false
#⇒ true
String.to_existing_atom "true"
#⇒ true
I've been looking all over the place and I'm wondering if I'm doing something wrong. And just to double check, I'll ask you guys!
So I'm receiving params in a Rails controller. One key, value pair is :status => true/false. However, I find that when I try to post status as a string like
:status => "THIS IS NOT A BOOLEAN"
and create my object in my controller, the :status attribute of my object becomes false.
Therefore, is there any clean way in rails to validate that my :status corresponds to a boolean?
Thanks!
This very strange method will to the trick
def is_boolean?(item)
!!item == item
end
params[:status] = 'some string'
is_boolean?(params[:status])
# => false
params[:status] = true
is_boolean?(params[:status])
# => true
A slightly more intuitive version would be
def is_boolean?(item)
item == false || item == true
end
Validation
The Rails way to do it is to validate in the model (from the docs):
#app/models/model.rb
Class Model < ActiveRecord::Base
validates :status, inclusion: { in: [true, false] }, message: "True / False Required!"
end
--
MVC
The reason for this is twofold:
DRY
MVC
If you want to keep your application DRY, you need to make sure you have only one reference to a validation throughout. Known as the "Single Source Of Truth", it means if you try and populate the model with other controllers / methods, you'll still invoke the same validation
Secondly, you need to consider the MVC (Model-View-Controller) pattern. MVC is a core aspect of Rails, and means you have to use your controller to collate data only - pulling & compiling data in the model. This is also true for validations -- always make sure you keep your validations with the data (IE in the model)
The above #Iceman solution is good if you are only doing it once place but you keep doing/repeating it in other places i suggest you to create to_bool method. i.e
class String
def to_bool
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
end
end
and put this method in intializer or in library. And, you can simply do this
Mymodel.new(status: params[:status].to_s.to_bool)
we are doing to_s just because to convert nil to '' incase the status key isn't in params .
So I know that hstore only stores in string either key and especially value. I'm looking for a way to set their datatypes. Is there a way in rails or hstore to do this?
So far what I did was to override the getters and depending on the datatype I want. This is what I have so far:
class ModelWithHstore < ActiveRecord::Base
store_accessor :properties, :some_boolean_field, :some_integer_field, :some_datetime_field
validate :validate_range
def some_boolean_field
return if self[:properties].nil? || self[:properties][__method__.to_s].nil?
if [true, 'true', '1'].include? self[:properties][__method__.to_s]
return true
elsif [false, 'false', '0'].include? self[:properties][__method__.to_s]
return false
end
self[:properties][__method__.to_s]
end
def some_integer_field
return if self[:properties].nil? || self[:properties][__method__.to_s].nil?
self[:properties][__method__.to_s].to_i
end
def some_datetime_field
return if self[:properties].nil? || self[:properties][__method__.to_s].nil?
DateTime.strptime(self[:properties][__method__.to_s].to_s, '%F %T')
end
private
def validate_range
errors.add(:some_integer_field, "value out of range") if !some_integer_field.between?(10, 90)
end
end
And since they are getters. I think they are being used too in validators and some other places. But I really am not sure if something like this already exists or is there a better way to implement this.
Cheers!
You can try hstore_accessor gem
I have an array
ABC = ["A","B","C"]
<%= f.select :abc, model::ABC, :include_blank => true %>
If I select C, then I want to display an input field for "city" and "state". Otherwise, those fields should be hidden. Is there any simple way of doing this. I don't want to use jQuery or Ajax.
I don't know of a way to change what fields are being displayed without using javascript.
What you could do is always display the city and state fields, but only require them if the select menu is set to C. For example, define a validation rule that requires a field if the select menu is set to C. In your lib/ directory, make require_if_c_validator.rb
class RequireIfCValidator < ActiveModel::EachValidator
def validate_each object, attribute, value
if object.your_attribute_name == 'C' && value == nil
object.errors[attribute] < 'is required'
end
end
end
And then in your model, call it on city and state:
validate :city, :require_if_c => true
validate :state, :require_if_c => true
We have an ActiveRecord model whose columns have some default values. It also has a validation condition such that, if the 'profile' property is set to a different value, then the default values are invalid.
What I'd like is to be able to determine whether the attributes have been set since they were set to the default so that I can reset them to new, valid values before validation.
Is this possible?
UPDATE: It's not clear what I mean, so I should give code examples.
The table is defined like this:
t.column :profile, :string
t.column :contact_by, :string, :default => "phone", :null => false
The validation is like this:
validate :validate_contact_by_for_profile1
def validate_contact_by
if (profile == "profile1") && (contact_by != "email")
errors.add(:contact_by, " must be 'email' for users in profile1")
end
end
So any time we do this:
u = User.new
u.profile => profile1
We end up with u being invalid. What I want to end up with is that the user's contact_by defaults to "phone", but if their profile is set to profile1, then it changes to "email", unless it has been set to something in the meantime. (Ideally this includes setting it to "phone")
EDITED ANSWER:
ok, don't know if I understood, but I'll try :P
you can writing a method to ovveride the profile= setter:
def profile=(value)
self.contact_by = 'email' if value == 'profile1'
super
end
this way works as you expect:
> n = YourModel.new
=> #<YourModel id: nil, profile: nil, contact_by: "phone", ...>
> n.profile = 'profile2'
=> "profile2"
> n.contact_by
=> "phone"
> n.profile = 'profile1'
=> "profile1"
> n.contact_by
=> "email"
as you can see, this way you get want you want. then you can do whatever validation you need .
hope this time helped ;-)
OLD ANSWER:
generally, you set default values during db migration. so when you try to save some data, the ActiveRecord model has blank data, then when saved on db, it gets default values.
according to this, you can play with validations in the model using something like this:
validates_presence_of :some_field, :if => Proc.new {|m| p.profile != <default value>}
alternatively, you can write a custom validation code, as private method, that will be called from validate:
validate :your_custom_validation_method, :if => Proc.new {|m| p.profile != <default value>}
btw I suggest you to look at ActiveRecord validations docs: http://guides.rails.info/active_record_validations_callbacks.html