For rails 4 Strong Parameters I need to access two of the fields. How can I do that?
def branch_params
params.require(:branch).permit( :equal_number, :equal_main_branch_number,
:history, :inquiry_email, :internal_notes,
:is_main_branch, :main_branch_number, :name,
:number,:region_id, :serving )
end
I understand this part. Strong Parameters
def create
#branch = Branch.new(branch_params)
end
Now I need to pass two of the fields to pass into a method.
format_branch_number(:equal_number, :equal_main_branch_number)
According to docs
Action Controller parameters are forbidden to be used in Active Model
mass assignments until they have been whitelisted
what means, you cant use them to create AR object, but you can still use your params to do some stuff with them, so you can simply format_branch_number(params[:equal_number], params[:equal_main_branch_number])
try this:
format_branch_number(params[:branch][:equal_number], params[:branch][:equal_main_branch_number])
Related
How can i use query parameter as a strong parameter.
This is my POST /tag method called by frontend to search posts.
def tag
if params[:category] == 'Shop'
render json: ShopPostPopulator.new(params[:search]).run
else
render json: Part.search(params[:search])
end
end
If i want to use strong parameter instead of 'params[:search]', how should I do it.
ActionController::Parameters is really just a hash like object and "strong parameters" is really just the equivalent of using Hash#slice to only allow a whitelist of attributes through. Which protects against mass assignment attacks. Beginners and often experienced Rails devs. seem to think that it magically filters and cleans the parameters. It doesn't - it just prevents you from getting a mass injection attack out of ignorance, stupidy or laziness.
Whitelisting is only needed if you are assigning a hash of parameters to a model:
User.update(
params.permit(:email, :password)
)
In this case it prevents a malicious user from for example passing role=superadmin or id=1 (as the first user is often the admin). If you are just assigning a single attribute from the params hash you don't need to use strong attributes. The major difference introduced back in 2012 is that whitelisting became manditory as an error is raised if you pass a ActionController::Parameters object without the #permitted = true attribute to .new, .update, .create and the other methods that spawn or update records.
If you want to though you can use ActionController::Parameters#permit to ensure that the parameter is a simple scalar type (not a hash or array):
params.permit(:search).fetch(:search, nil)
If search is an optional parameter with nested keys you can whitelist it like so:
params.fetch(:search, {}).permit(:foo, :bar)
You can also make the parameter required so that a ActionController::ParameterMissing exception is raised if its missing:
params.require(:search).permit(:foo, :bar)
Which is what you do 99% of the time in Rails since it bails early if we can't do anything meaning with the request.
In rails I did this in a model:
def update_user_ex(*attrs)
user.assign_attributes(*attrs)
# .............
where attrs is an array with of a hash(es), for simplicity let's say it's a single hash.
How can I do this in Rails 4? "permit" doesn't work on a hash or array.
It's possible to use strong parameters outside of controllers per the documentation at https://github.com/rails/strong_parameters
Example:
def update_user_ex(*attrs)
params = ActionController::Parameters.new(attrs)
user.assign_attributes(params.permit(:name, :email, :something_else))
Permit do work on arrays in rails 4. But array need to be last parameter.
params.require(:test).permit(:name,:rollno, question_ids:[])
The below example give error as array is not last parameter.
params.require(:test).permit(question_ids:[], :rollno)
As title says, why does Rails prefer to use the #params variable inside of a Controller action when you are responding to the action instead of passing the individual parameters through the function arguments when we call the function?
Other frameworks use this (i.e, ASP MVC) and I was just wondering if there was a reason for that design decision, because it doesn't seem very intuitive.
Ie. Why does Rails do
def index
name = params[:name]
end
Instead of
def index(name)
end
The point is, most of the actions in a controller handles the view REST-fully. The params comes from the user's browser when they interact with the page or send a new variable request to the page.
These requests are variable, and Rails makes it uniform by maintaining the parameters in params hash. If the following GET requests arrive:
http://localhost:3000/products?color=red&quality=best
the params hash will automatically be populated as {'color' => 'red', 'quality' => 'best'}. Rails doesn't expect your action to manually handle the parameters.
Similarly, consider you are getting a POST request from a page where a user filled a form. In that scenario, the params obtain the parameters which are composed with form helpers inside views.
Though in hyptothetical case you are dealing with general methods instead of actions, such as below, you will have to do it by passing arguments.
def show
if params['color'] == 'red'
#product = obtain_product('red')
else
#,..
end
end
def obtain_product(color)
Product.where('color = ?', color).first
end
Hope it is clear. :)
#kidorrails has a great answer, and I wanted to add to it:
If you wanted to pass the params to each method directly, it would go against the #1 Rails convention - keep it DRY. By having a separate params hash, you not only have access to all the params you want, but you can access them through as many methods as you need
For example, take strong_params:
#controller
def new
#model = Model.new
end
def create
#model = Model.new(strong_params)
#model.save
end
private
def strong_params
params.require(:model).permit(:your, :params)
end
As #apneadiving mentioned, the params hash is created in another part of the stack, meaning it's available over all the methods required. It's most efficient & versatile way to do it IMO
I am creating a instance variable that gets passed to my view. This variable 'post' has a user_id associated with it and I wanted to add an extra attribute called 'username' so I can also pass that and use it in the view.
Here is an example of what I would like to do.
#post = Post.find(params[:id])
#post.username = User.find(#post.user_id).username
A username column does exist on my Users model but not my Songs model. So it won't let me use
#post.username
I know I can just make an entirely new instance variable and put that information in there but I would like to keep everything nice and neat, in one variable. Which will also make my json rendered code look cleaner.
Any ideas on how I can accomplish this?
Thanks!
Based on the presence of a user_id in your Post model, you probably already have an association set up that can retrieve the username. It will probably save a lot of trouble to simply use the existing association:
#post = Post.find(params[:id])
username = #post.user.username
If you're likely to be querying more than one post at a time (e.g., on an index page, calling .includes to tell Rails to eager-load an association will help you avoid the N+1 problem:
#posts = Post.includes(:user).all
Finally, to include the associated record in your JSON output, pass the :include parameter as you serialize:
# in controller
render :json => #post.to_json(:include => :user)
This question includes a much more comprehensive discussion of serialization options. Well worth a read.
No need to pass a separate instance variable.
1. You can use #post.user.username in view itself.
2. Or you can create a helper and pass #post.user
def username user
user.username
end
I've got a form with quite a bit of params being passed to the controller for processing. The different 'sets' of params are named in a similar fashion:
setname1_paramname
setname1_paramname2
Now, I need to check one of these 'sets' to verify that all of the fields are submitted. Right now, I'm doing this with a manual If Or style statement:
if setname1_paramname.blank? || setname1_paramname2.blank? || ...etc
#object.errors.add_to_base("All setname1 fields are required.").
render :action => 'new'
return false
end
Is there way to programmatically loop over these params, and add them to the #object errors?
Thanks!
Since it sounds like you have a ton of params and also seems like you need to be able to do checks on groups of params, maybe something like this would be useful? Basically, iterate over the params hash, and use regular expressions to target sets of params. Then, inside the loop, you can do any sort of validations:
params.each do |key, value|
# target groups using regular expressions
if (key.to_s[/setname1.*/])
# whatever logic you need for params that start with 'setname1'
if param[key].blank?
#object.errors.add_to_base("All setname1 fields are required.").
end
end
end
If the names are arbitrary and of your own choosing, you could make virtual attributes for them in your model and let Rails handle the presence checking.
class SomeModel < ActiveRecord::Base
VIRTUAL_ATTRIBUTES = [:billing_address, :billing_state, :something_else]
attr_accessor *VIRTUAL_ATTRIBUTES
validates_presence_of *VIRTUAL_ATTRIBUTES
…
end
Is there a reason you wouldn't just store this information in a model, even if temporarily, and then just use rails validations for your information?
I'm rusty but I assume that even if the value is blank the param will still be returned in the params hash as long as it is coming from a form element, yes? Could you just iterate through the params hash and keep a counter of how many values are not blank and then compare the length of the params hash to the counter. If the counter is short then you have blank parameters and can handle the error that way without having to hardcode checks for each individual parameter, yes?
If what you need is a multi-step form as I suspect, you may find the Railscast on Multistep Forms to be useful