I have an action controller to validate params that are coming from view.
def duplicate
#params to be validated
params = params[:group_to_duplicate]
#params have to be validated to avoid method 'find' for some reason
group = Group.find(params[:id])
#validate to avoid this 'if'
if group
group.duplicate params
notice = 'Some message'
else
notice = 'Some other message'
end
redirect_to groups_path, notice: notice
end
How to validate the request parameters coming from view, like laravel 5 enter link description here?
Sometimes you do need to validate request params, and not the model.
API's for example. You often need to validate the params given. Maybe you require a date range for an API that returns stock quotes.
The quote model is valid, but in order to fetch it properly you need to know the range the user needs because you don't allow them to have the entire quote history. Something like that.
Also in the case of a search form. Maybe you have a form that requires the user to type the last name before searching for an employee.
In these cases you can use form or view objects to help with the validation.
Here's quick article on form objects:
https://robots.thoughtbot.com/activemodel-form-objects
I've been looking at this as well. I'm going to give this a shot when I get some free time:
https://github.com/nicolasblanco/rails_param
In most cases, you should not have to validate request parameters in your controller.
The best practice for model form validations (required, unique, length, max, etc. ) is to define validations in the model i.e. /models/group.rb, and use a form library such as simple_form which automatically handles the model validations you've defined.
For example, in your group.rb you'll have:
class Group < ActiveRecord::Base
validates :group, presence: true
end
If you absolutely need to validate in your controller, use Action Controller Filters: http://guides.rubyonrails.org/action_controller_overview.html#filters
References:
http://guides.rubyonrails.org/active_record_validations.html
https://github.com/plataformatec/simple_form
Related
Good Day All!
Edited for better understanding.
First model is Inventory and in this model I have Product_Type, Product_Name and User_ID.
Second model I have Users which consist of First_Name, Last_Name and Pin_Number.
On my Inventories page I have a form for checking out said Product_Type and Product_Name, also a place for a user to put their Pin_Number in. On submit, it will check the Pin_Number they have typed in and validate it in the Users model and if the Pin_Number is correct it will create an entry with said Product_Type, Product_Name and User_ID (which is pulled from Pin_Number that was submitted.)
I am just trying to figure out how to validate that Pin_Number they submitted.
Thats why I thought I had to do some kind of validation and an if statement based on that validation. Not sure how to go about that.
I hope this clears up any confusion.
I am just trying to figure out how to validate that Pin_Number they submitted.
What constitutes a valid pin_number? Just that it allows you to successfully look up a User? What if a user enters another user's pin_number? Is that considered 'valid'? Something to think about...
It would be helpful if you would add to your question what your params look like upon form submission. But, we can do some guess work.
So, let's assume that params looks something like:
{..., "inventory"=>{"product_type"=>"foo", "product_name"=>"Bar"}, "pin_number"=>5, ...}
In your controller, you'll probably do something like:
if #user = User.find_by(pin_number: params[:pin_number])
#inventory = Inventory.new(inventory_params)
#inventory.user = #user
if #inventory.valid?
#inventory.save
# perhaps do some other stuff...
else
# handle the case where the `#inventory` is not valid
end
else
# handle the case where the `#user` was not found
end
This assumes you have something like:
private
def inventory_params
params.require(:inventory).permit(:product_type, :product_name)
end
In your Inventory model, you probably want to do something like (I apologize, I'm not on Rails 5 yet, so some of the syntax may be incorrect):
class Inventory < ActiveRecord::Base
validates :user_id,
:product_type,
:product_name,
presence: true
belongs_to :user
end
You probably also want to consider adding an index on User.pin_number if you're going to be doing a lot of finding by it.
Not sure if I got the question right, but sounds like a custom validator to me.
You can learn more about custom validators in the official Rails documentation under "Custom Validators"
Also, consider moving the class for the custom validator you'll build to a concern, which is a great way to make it reusable. You can find more information on this StackOverflow question and this nice tutorial.
I'd not claim myself to be an expert in Rails by any stretch. One of the things that confuses me is Strong Parameters, and I've not found any really straightforward tutorials on it, with the majority of the search results dominated by hits on the rails documentation which, whilst normally accurate, I don't find in any way easy to read and can't be considered a tutorial. The github for strong params also doesn't appear to cover this.
Say I have an entity called "Resource".
class ResourcesController < ApplicationController
...
def create
#resource = Resource.new(resource_params)
if #resource.save
...
respond_with(#resource.level)
else
...
end
end
def update
if #resource.update(resource_params)
...
respond_with(#resource.level)
else
...
end
end
...
def resource_params
params.require(:resource).permit(:name, :url, :description, :level_id)
end
end
Assume I have a scaffolded form which displays the fields for name, url, description and level_id. All of the fields are mandatory. I don't know how to amend the resource_params function to ensure that name, url and level_id are mandatory when updating (or creating) a resource, but that description is optional (but should still be permitted).
I've tried removing description from the require line, and adding it on a separate line as params.permit(:description) but that has not made any difference, the field is still mandatory in the form.
Any assistance on this would be welcomed!
As I said, this is nothing to do with strong parameters. You just need to remove required: true for that field to make it optional.
I think you should think about :on
http://guides.rubyonrails.org/active_record_validations.html#on
validates :email, uniqueness: true, on: :create
It enables validations only on specified action.
Strong parameters are used to ensure that no other data can pass into your object, that no1 can insert not wanted data. For example if you have entity User and it has field admin that if it is true, the user has admin role, it can not be set using the create or update method inside your controller, because some1 can send any kind of parameters to your controller, and you want to filter them (Allow only specific parameters).
This does not mean if you put something inside strong parameters that it is required for create, update or whatever. Strong parameters only are there to filter the data, and allow only certain parts of your entity to be settable through this service or REST. If you send parameters that are not in strong params defined, in your server console/log there will be unpermited parameters: list of the parameters.
Rails noob ,
I am trying to write a custom validation but I am dependent on parameters that come from the post request. This example is similar to what I have - in this post model I want to validate that a user didn't already post on some topic, but to do that I have to have the topic id from the post request:
class Post < ActiveRecord::Base
...
validate :user_already_posted, on: :create
def user_already_posted
topic=Topic.where(id: params[:topicId]).first
//some code that runs on topic users and makes sure the user hasn't posted there
However , I learned that params isn't global and models can't access it (I last used laravel where this isn't the case , so it's confusing for me).
Are custom validations not suited for what I need ? do I need to look at filters or have the controller run a validating function of it's own?
You could do this:
validates_uniqueness_of :user, scope: :topic_id
May not be exactly what you need, but the point is that you can validate within a scope.
You can also pass an array to validate on multiple parameters.
validates_uniqueness_of :user, scope: [:topic_id, :post_id]
I think you are having a bit of a design problem here. You are creating a post validator, but the validation itself is not about the post instance. I mean, the model validator must evaluate all of the post attributes, using the default validators built-in ActiveRecord or creating custom ones, like you did, acessing the attributes via self.
I believe a class method receiving all your parameters and checking the conditions of the post creation is more clear:
Class method on the model
def self.user_already_posted(topic_id, user_id)
# Do your thing
end
Usage on the controller
can_create = Post.user_already_posted(params[:topic_id], params[:user_id)
I have two models
class Information < ActiveRecord::Base
belongs_to :study
validates_presence_of :email
end
and
class Study < ActiveRecord::Base
has_many :informations
accepts_nested_attributes_for :informations
end
I show up a form of study which contains few fields for the informations and i want to validate presence of those fields. Only on validation success i wanted to save the study field values as well and i wanted to show errors if the validation fails. How can i do this? Thanks in advance.
You write validations in the models that you require, as normal. So if you need to validate presence of field foo in the Information class you'd just write validates_presence_of :foo in that class. Likewise validations for Study fields just go in the Study class. With nested attributes, when you update a Study instance from a params hash that contains nested attributes, it'll update the Information instance(s) too, running validations in passing. That's what the accepts_nested_attributes_for call is doing - it's giving "permission" for the appropriate bits of a params hash to be used in this way.
You can use reject_if to only reject new nested records should they fail to meet criteria. So I might let someone create a Study and only create one or more nested Information instances associated with that Study if they'd filled in field(s) in the form, but if they left them blank, the nested stuff wouldn't be created and saved (so you don't get pointless blank associated records). The Study would still be saved. For example:
accepts_nested_attributes_for(
:informations,
reject_if: proc() { | attrs | attrs[ 'title' ] .blank? }
)
This and more is covered in the API documentation here:
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Beware that nested fields are intended for existing records only. If you were creating a new Study instance in a new/create action with no Information instances associated, you won't see any nested form fields for your Information class at all - when you might be expecting just one, for a blank new item. This can be very confusing if you aren't ready for it! You'll need to manually add a new Information instance to your Study instance in the controller or similar for the 'new' and 'create' actions, e.g. using before_filter :create_blank_object, only: [ :new, :create ], with, say:
def create_blank_object
#study = Study.new
#study.informations << Information.new
end
you can use validates_presence validation available in rails other wise you can write before_create or before_save callback method. write validation logic inside the before_create or before_save callback method.
Check out the API Doc for validates_associated:
Validates whether the associated object or objects are all valid. Works with any kind of association.
If you call a method on the parent object which runs validations (e.g. save), the validation on the associated objects will be called as well.
I am not finding any great examples online and so am asking an easy question for what I expect will get an easy answer. Be gentle. :)
I have a Post model.
p = Post.find(1)
p.title = "This is the Title of this Article"
p.url_title = "this-is-the-title-of-this-article--created-by-user-name"
When the Post is created, I create the :url_title based off the title. This is how I key off it in the database rather than exposing IDs which are also boring and non-descriptive.
I build this :url_title in a before_save so that is why I can't simply use 'validates_uniqueness_of' because it looks like the validations are done before the before_save kicks in and there is a :url_title to validate.
So, I need to ensure that :url_title is unique. I append the "--created-by-#{p.user.name}" to allow for there to be multiple uses of the same title from different users.
So, what I need to do is have a custom validation that confirms that :url_title is unique to the database before saving and, if it is not unique, raises and error and informs the user.
Thoughts on the best way to do this?
'
You can move your callback from before_save to before_validation (see here). This callback will be run on create and update action, so I think it will be sufficient for your needs.
Use this to create the url_title
before_validation_on_create :create_url_title
....
private
def create_url_title
url_title = .....
end
Then add the proper validation to url_title
validate_uniqueness_of :url_title, :message => "This title is taken, please choose a different title"
Just add
validates_uniqueness_of :url_title
in your Post model