In my model I have the following validator:
validates :terms, acceptance: true, on: :create, allow_nil: false
attr_accessor :terms
and in my form I have:
= simple_form_for #reservation do |f|
= f.error_notification
= f.input :terms, as: :boolean
The problem is that when user not accept the terms it not showing any error, why?
Try this:
validates :terms, :acceptance => {:accept => true} , on: :create, allow_nil: false
Problem may have terms as an actual column in the table. In general validates_acceptance_of is used without such a column, in which case it defines an attribute accessor and uses that for its validation.
In order for validates_acceptance_of to work when it maps to a real table column it is necessary to pass the :accept option, like:
validates :terms, :acceptance => {:accept => true} , :on => :create , allow_nil: false
The reason for this has to do with typecasting in Active Record. When the named attribute actually exists, AR performs typecasting based on the database column type. In most cases the acceptance column will be defined as a boolean and so model_object.terms will return true or false.
When there's no such column attr_accessor :terms simply returns the value passed in to the model object from the params hash which will normally be "1" from a checkbox.
Via noodl
I may have had a similar problem (Rails 4.2.0). I created a checkbox, but it would be ignored and never report and error if unchecked. I found that adding the parameter to the .permit part of my Strong Parameters allowed it to be present.
In my view template for my _form I have something like this:
<div class="field">
<%= label_tag :tos, 'I accepts the TOS' %><br>
<%= f.check_box :tos %>
</div>
I generated my model using scaffold, so my create method start like this
def create
#thing = Thing.new(thing_params)
then near the bottom I have the following for thing_params
def thing_params
params.require(:thing).permit(:field1, :field2, :tos)
end
in my model I used the following:
validates_acceptance_of :tos
If I leave out ':toslike thisparams.require(:thing).permit(:field1, :field2) it will not pop up an error and allows it to continue. This seems counter-intuitive because if Strong Parameters is removing the :tos field then I would think the validate_acceptance would fail.
I had initially just create a checkbox without using f.check_box. Now, if I even try to call the new route without :tos" being listed as permitted, rails throws an error. There also seems to be some rails magic going on because if I remove the validates_acceptance_of from my model, I receive an NoMethodError error when rendering my view saying undefined methodtos'` for the line
<%= f.check_box :tos %>
Would be great if someone else could explain what exactly is going on as I just hacked this together from googling and guessing.
Related
I have looked at loads of different articles on the web (some on here) about this issue but there are so many different suggestions, lots of which are outdated, that it has led me to ask here today...
I have a field in my Users table called admin? which is a :boolean data type. I also have a checkbox in the form in my view called admin? - I would like to be able to create TRUE and FALSE accordingly in the table record when the form is submitted.
Part of my view code is:
Admin User? <%= f.check_box :admin? %>
Also I have permitted this in my post_params - is this a necessary step?
params.require(:staff).permit(:name, :email, :password, :password_confirmation, :admin?)
When I submit the form at the moment, the admin? field is unaffected. Any advice would be much appreciated.
No need to name it ":admin?"
Just use this in your form:
Admin User? <%= f.check_box :admin %>
And the permitted params like this:
params.require(:staff).permit(:name, :email, :password, :password_confirmation, :admin)
That should work.
For anyone that has a form that isn't part of an object.
I found using checkbox syntax like:
= check_box 'do_this', '', {}, 'true', 'false'
Then in the controller side:
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(params[:do_this])
Will give you the correct boolean value of do_this.
Examples:
[1] pry(main)> ActiveRecord::ConnectionAdapters::Column.value_to_boolean("true")
=> true
[2] pry(main)> ActiveRecord::ConnectionAdapters::Column.value_to_boolean("false")
=> false
[3] pry(main)> ActiveRecord::ConnectionAdapters::Column.value_to_boolean("1")
=> true
[4] pry(main)> ActiveRecord::ConnectionAdapters::Column.value_to_boolean("0")
=> false
Edit:
The above is deprecated, use:
ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
It gives the same results as the examples above.
Rails 5
The above options don't work in Rails 5. Instead, use the following:
ActiveRecord::Type::Boolean.new.cast(value)
It's possible you have not allowed your controller to accept the admin field through params. In other words, an issue of strong parameters. Ensure that :admin is permitted in your model_params.
In my app I have a validation rule like this
validates_presence_of :name, :on => :custom_context
When I'm saving my data I use
#obj.save(:context => :custom_context)
So that my context validation rule is applied. This works fine. By in my form, the name field is not marked with asterisk. How can I tell my form helper that we are in the :custom_context context and the name field must be marked as required?
I did not understand what you are trying to do BUT understood the scenario.
You can use an attribute_accessor in your model say -
attribute_accessor :context
In your view(.html.erb file) do the following inside your <% form_for %>
<%= f.hidden_field :context, :value => "custom_context" %>
And in your model :
validates_presence_of :name, :if => Proc.new { |variable|
variable.context == "custom_context"}
I think this should help :D
OK, I guess there is no perfect way to do this. Eventually I did something like this:
<%= f.input :name, :required => required_in_context?(:name, :custom_context) %>
And I wrote a helper method:
def required_in_context? field, context
required = false
MyClass.validators.each do |v|
required = true if v.kind == :presence && v.attributes.include?(field) && v.options == {:on => context}
end
required
end
I have a Rails model (persisted with Mongoid) that can be collaboratively edited by any registered user. However, I want to allow editing any particular attribute only if it was previously blank or nil.
For example, say someone created an object, and set its title attribute to "Test Product". Then another user comes along and wants to add a value for price, which until now has been nil.
What's the best way to do this, while locking an attribute that has previously been entered?
Look into the ActiveRecord::Dirty module for some nice utility methods you can use to do something like this:
NON_UPDATABLE_ATTRIBUTES = [:name, :title, :price]
before_validation :check_for_previously_set_attributes
private
def check_for_previously_set_attributes
NON_UPDATABLE_ATTRIBUTES.each do |att|
att = att.to_s
# changes[att] will be an array of [prev_value, new_value] if the attribute has been changed
errors.add(att, "cannot be updated because it has previously been set") if changes[att] && changes[att].first.present?
end
end
The easiest way, i think, is by checking for it in the form itself.
Just say add :disabled => true to the input field if the person cannot edit it.
<% if #my_object.name %>
<%= f.text_field :name, :disabled => true %>
<% else %>
<%= f.text_field :name, :disabled => true %>
<% end %>
(i think there is a prettier way to write this code)
But by using this the user has a visual feed back that he can't do something, it is always better to not allor something than to give an error message
I'm trying to fill out an array with values from checkboxes. It works just fine when creating a record, but fails validation when editing. The params look right, which is what really confuses me:
"record"=>{... "type_array"=>["accounting"], ...}
It looks the same as the params from creating a new record. The fields in New.html.erb and Edit.html.erb also use the same markup.
Edit.html.erb
<div class="field">
<%= f.label :type_array, "What type of record?" %><br />
<% ["accounting", "agriculture", "automotive"].each do |type| %>
<%= check_box_tag 'record[type_array][]', type, (true if #record.type_list.include? type),
:id => type %>
<%= label_tag type, type.titleize, :class => type %><br />
<% end %>
</div>
Parts of Record.rb
validates :type_array, :presence => true
attr_accessor :type_array
attr_accessible :type_array
before_validation :set_type_list
private
def set_type_list
self.type_list = type_array.join ',' if type_array.present?
end
Am I missing something? When I remove the type_array validation and fill out the form, it acts like type_array is empty. Somewhere along the line, it must be lost or something.
I appreciate any help.
(Sidenote: if anyone has a better way to do the list of checkboxes, let me know)
Delete the line attr_accessor :type_array.
This creates accessor methods to a new instance variable, not to the model attribute type_array, which means that #record.type_array now refers to that instance variable instead of the attribute.
You almost never use attr_accessor or it's siblings attr_reader and attr_writer in Rails because you want to deal with model attributes, not instance variables.
Edit: You're using type_array as a virtual attribute.
class Record < ActiveRecord::Base
validates :type_array, :presence => true
attr_accessible :type_array
def type_array=(val)
self.type_list = val.join ','
end
def type_array
self.type_list.split ','
end
def type_array_before_type_cast
type_array
end
end
For the reason why you need that last function definition, see this question.
I generated a simple Post scaffold which has title:string body:text category:string. I later added type:string (and performed the migration) to the model and added the selection fields in new.html.erb and edit.html.erb. I also added validation for all these fields.
<%= f.label :type %>
<%= f.select :type, Post::TYPES, :prompt => "Select post type" %>
When I try and create a post it gives me:
"There were problems with the following fields:
Type can't be blank
Type is not included in the list"
Even though I DO make a selection. Am I missing something obvious here?
Select code from Post class:
TYPES = [
["Job", "job"],
["Volunteer", "vol"]
]
validates_presence_of :title, :body, :category, :type
validates_inclusion_of :category, :in => CATEGORIES.map {|disp, value| value}
validates_inclusion_of :type, :in => TYPES.map {|disp, value| value}
The type field is a reserved field used for single table inheritance(STI). You have to rename the field.
Refer to this article for more details
Edit: Changed the link to point to the article provide by Matchu.
If you really want to, you can use field called type in Rails 4 by setting inheritance_column to something else:
class Product < ActiveRecord::Base
self.inheritance_column = :ruby_type
end
In Rails 3 and below, use method set_inheritance_column instead.