I am trying to add a validation to a simple form in a Rails 4.1 project. I need to reject a form submission if a text field contains a forbidden word. My other validations work but not this one. So if the user enters no value or too long of a value it is rejected and the error message is displayed.
I have it setup similarly to the edge guide (http://edgeguides.rubyonrails.org/active_record_validations.html#exclusion) but the form submit still goes through if I enter "My favorite color is red." What should I do differently?
My model:
class ColorEntry < ActiveRecord::Base
validates :body, presence: true
validates :body, length: { maximum: 255 }
validates :body, exclusion: { in: %w(red) }
end
Try to use a regex validation for format with the "without" attribute. So, if it does not match, the form can't be submitted.
validates :body, format: {without: /example/}
Other syntax
validates_format_of :body, without: /example/
More references in:
http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html
Related
I just started trying my hands on Ruby on rails . i have created a mode states and want that every state name must remain unique so i used
uniqueness: true
as per http://guides.rubyonrails.org/active_record_validations.html .
As the above document says that the validation is invoked automatically when object.save is called. but When i try to save the objects with same state_name value , no exception is thrown and the record is saved. Can one please help where i am doing it wrong.
Model code
class State < ActiveRecord::Base
acts_as_paranoid
validates_presence_of :state_name ,uniqueness: true
end
Controller code
def create
#stateName = params[:stateName];
#state = State.new();
#state.state_name=#stateName;
if(#state.save())
resp = { :message => "success" }
else
resp = { :message => "fail" }
end
respond_to do |format|
format.json { render :json => resp }
end
end
Thanks in advance for helping!
If you want uniqueness check, change
validates_presence_of :state_name ,uniqueness: true
to
validates :state_name, uniqueness: true
If you want uniqueness and presence check both, use
validates :state_name, uniqueness: true, presence: true
An alternate syntax is shown below, however, syntax shown above should be preferred
validates_uniqueness_of :fname
validates_presence_of :fname
Also, as per documentation, please note following with respect to usage of uniqueness: true
It does not create a uniqueness constraint in the database, so it may
happen that two different database connections create two records with
the same value for a column that you intend to be unique. To avoid
that, you must create a unique index on both columns in your database.
The validation happens by performing an SQL query into the model's
table, searching for an existing record with the same value in that
attribute.
What this means is that it is possible that if multiple users are trying to save records concurrently, there is a possibility records with duplicate state_name can get created as each save is happening on different thread
I want a validation in my organisations model that runs only, when an image file is selected for upload.
app/models/organisation.rb
class Organisation < ActiveRecord::Base
validates :name, :url, :street, :city, :zipcode, presence: true
validate :validate_minimum_image_size, if: # file is selected for upload
def validate_minimum_image_size
image = MiniMagick::Image.open(picture.path)
unless image[:width] > 300 && image[:height] > 300
errors.add :image, "should be 300px minimum!"
end
end
end
Is there a way to check image size when the image file is selected to upload?
You can provide your own custom method sth like :
validate :validate_minimum_image_size, if: :file_present?
def file_present?
picture ? true : false
end
I have a polymorphic lookups table with a child ContractType model. I have a before_save callback in the ContractType model that sets a category, but it doesn't seem to be working.
class Lookup < ActiveRecord::Base
validates :value, presence: true
validates :category, presence: true
end
class ContractType < Lookup
before_save { self.category = "contract_type" }
end
Then I open the rails c:
> c = ContractType.create(value: "test")
> c.errors.messages
=> { :category => ["can't be blank"] }
I don't get any errors, just a failed validation. As far as I know, the syntax looks correct, it's just that the before_save callback doesn't seem to be working...
Am I missing something obvious here?
I found the problem...validations take place BEFORE the save, so it always "failed" validation and stopped before the before_save callback took place.
The solution is to use a before_validation callback.
class ContractType < Lookup
before_validation { self.category = "contract_type" }
end
My misunderstanding of the order of events.
I know you found your solution, but think about your problem and solution logically. You are hard coding the category value. It means that the user cannot leave it blank. It will always be filled. So why have a validation for it in the first place? Just remove this:
validates :category, presence: true
In the before_save callback, you will know the value will be assigned. before_validation does have use cases. For example, a user enters a value for a currency attribute and you want to format the currency prior to validation. But in your case, before_validation is not needed.
I want to use a currency input with simple form rails 4.
I have a in my model.
field :minimum_salary, type: Integer
I am using rails 4 simple form, I added a inputs/currency_input.rb as follow:
class CurrencyInput < SimpleForm::Inputs::Base
def input(wrapper_options)
"$ #{#builder.text_field(attribute_name, input_html_options)}".html_safe
end
end
and in my form:
<%= j.input :minimum_salary, as: :currency, placeholder: "minimum", label: false %>
But it is not working. I have the following error:
ArgumentError - wrong number of arguments (0 for 1):
Just remove this wrapper_options i guess it should works.
class CurrencyInput < SimpleForm::Inputs::Base
def input
input_html_options[:type] ||= "text"
"$ #{#builder.text_field(attribute_name, input_html_options)}".html_safe
end
end
Stollen form this. You can also use mask as it mentioned by link article.
When I try to register an user, it does not give me any error but just cannot save the user.
I don't have attr_accessible. I'm not sure what I am missing. Please help me.
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :email, presence: true,
uniqueness: true,
format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
validates :password, presence: true, length: {minimum: 6}
validates :nickname, presence: true, uniqueness: true
end
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params) # Not saving #user ...
if #user.save
flash[:success] = "Successfully registered"
redirect_to videos_path
else
flash[:error] = "Cannot create an user, check the input and try again"
render :new
end
end
private
def user_params
params.require(:user).permit(:email, :password, :nickname)
end
end
Log:
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x5OqMgarqMFj17dVSuA8tVueg1dncS3YtkCfMzMpOUE=", "user"=>{"email"=>"example#example.com", "password"=>"[FILTERED]", "nickname"=>"example"}, "commit"=>"Register"}
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'example#example.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."nickname" = 'example' LIMIT 1
(0.1ms) rollback transaction
Regarding our short discussion in the comments, it appears that one or two things are happening to cause #user.save to return false:
One of the validation rules are failing
A callback within your model is returning false, thus halting processing and rolling back the transaction
There are a few quick ways to debug the validations. I figured I could describe them so you could learn a few options.
A. Change the call within the if statement to instead use the bang method of save:
if #user.save!
This will cause the app to raise an exception if validation fails, displaying the validation errors within the browser on your screen. In this particular scenario, you'd want to remember to remove the ! after you're done debugging because you probably don't want the final version of your app doing that.
Or...
B. Within the else statement, add this line:
raise #user.errors.to_yaml
This will display the validation errors within the browser on the screen. Of course, remember to remove this line after you're done debugging.
Or...
C. Within the else statement, add this line and then run the form post:
puts #user.errors.to_yaml
This will display the validation errors within your console. You'll want to remember to remove this line after you're done debugging, but it's "less worse" if you happen to forget because at least the extra info is only output to STDOUT.
You may want to try each of these just to get a little practice and to see what your options are in simple debugging scenarios like this.
High chances that error is in password confirmation. You use has_secure_password from Rails, which automagically handles password confirmation for you. And here is the problem - you don't have it before user creation. Thus just add. For details check out similar question on has_secure_password
And check, that you have password_digest:string in users table :)