I have a form_for which calls to a create method.
The create method is fairly typical, it calls a neighbouring method which houses the strong params:
Params.require(:blog).permit(:title, :body, :user_id, :access)
I create the record then with the following:
Blog.create(blog_params)
Though before I do that, I run a helper method which determines the value of :access - I assign the helper method directly to params[:access] as shown:
params[:access] = myHelper(val1, val2)
But this doesn't work, it just stays as a nil value. Currently, I'm having to do the following:
Blog.create(blog_params).update(access: params[:access])
Which is rather ugly and even dysfunctional when it comes to updating a record. What can I do to keep it tidy?
Your :access param actually lives in params[:blog][:access] before calling params.require(:blog)
So use:
params[:blog][:access] = myHelper(val1, val2)
Or:
bparams = blog_params
bparams[:access] = blog_params
Blog.create(bparams)
Related
In my controller I have this method:
def project_params
params.require(:project).permit(:name, :user_id)
end
And the create method. I check, if the logged in user #user, is the one for who the new project is made.
def create
new_params = project_params
return no_access if new_params[:user_id] != #user.id
...
end
And now my problem. I found out that when I POST the user_id as string via my API, the comparison doesn't make sense. As I compare String and Fixnum.
For example user_id = "10" and #user.id = 10.
One solution would be to use .to_i on the user_id parameter. However I have more cases than this example above.
So is there an easy way to automatically cast the params I get from project_params to the right class without changing the "require-permit" methods for every model in my project.
I didn't convert the values with .to_i in the first place as I thought rails gets the correct class from the respective database columns.
I have a problem with the mass-assignment and strong parameters. In my model I have several attributes, that are represented through a column in my mysql database. I also have a field, that isn't. I just need it to calculate a value. I don't want to store it in my database.
In my controller I defined the strong parameters:
def timeslots_params
params.require(:timeslot).permit(:employee_id, :dienstplan_id, :start_date, :start_time)
end
But when I'm trying to access the start_time attribute in my controller, I'm getting the
undefined method `start_time' for #<Timeslot:0x007fff2d5d8070> error.
The other defined parameters with db columns are present and filled with values. Do I missunderstand the strong parameters and have to define something else?
EDIT: Here is the code, where I call the timeslots_params:
def create
#e = Timeslot.new(timeslots_params)
#e.start_date = #e.start_date.to_s + " " + #e.start_time.to_s
if #e.save
current_user.timeslots << #e
respond_to do |format|
format.json { render :json => #e }
end
end
end
In your Model provide access to the start_time field:
attr_accessor :start_time
If you only need read access:
attr_reader :start_time
Please, permit only the params you expect your user send with data. If start_time is not user data for update your db, use this way:
params.require(:timeslot).permit(:employee_id, :dienstplan_id, :start_date)
Strong parameters prevents save data that user sends and you don't want he/she update.
If you use :start_time, it must be defined at your model.
Ops, I've seen your update:
#e.start_date = #e.start_date.to_s + " " + #e.start_time.to_s
If you send :start_time to an Timeslot instance them start_time must be a method of Timeslot model. Defined by rails if it is a db field, defined with attr_accesor or att_reader or defined by a def key on your source model.
If not #e.start_time trigger undefined method 'start_time'.
edited again:
Now, start_time is a model variable. Make sure it is send to the form in the same way that you do with the fields. By default we use an f <%= f.text_field :the_field %>. Just don't forget the f.
Now you must permit this field again, if you follow my first advice.
While Alireza's answer couldwork, you might also try defining the setter method yourself, then you can play with the variable before save.
def start_time=(time)
# use variable time to do what you want with the model
end
I am learning rails 4 and i am bit confused in some notation in the tutorial i am following. I am following Lynda Ruby on Rails 4 Essential Training.
I have a simple controller with crud actions. In New action i am assing the instance variable the parameter as this (with curly braces)
#subject = Subject.new({:name=>'default'})
But in Create actions I am doing this:
Subject.new(params[:subject])
redirect_to(:action=>'index')
Shouldn't this params[:subject] and :action=>'index' should also be inside the curly braces?
How can i know when to use curly braces and not?
params[:subject] will most probably return a value like
{:attr1 => 'value1', :attr2 => 'value2'}
Enclosing this in curly braces will result in
{{:attr1 => 'value1', :attr2 => 'value2'}} # Not a valid Hash/Syntax
But, render({:action => 'index'}) is same as without the curly braces. Ruby is intelligent enough to identify that it is a Hash without the curlies.
It is a common scenario to have a Hash as the last argument to a method.
def my_method(arg1, arg2, options={})
..
In this case, it is sometimes prefered to drop the {} as it could te mistaken for a block
my_method 1, 2, :opt1 => 'val1'
Strong Params
Something to add to Santosh's answer - you really need to consider the strong_params method when creating new ActiveRecord objects (if you want to save them):
#app/controllers/your_controller.rb
Class YourController < ApplicationController
def new
#model = Model.new
end
def create
#model = Model.new(model_params)
end
private
def model_params
params.require(:model).permit(:attributes, :for, :model)
end
end
--
Options
In terms of your redirect_to, I think Santosh covered the bases very well; however, you may wish to use just a symbol to denote loading an action:
redirect_to :index
By default, Rails will use the same controller you're on, allowing you to point to various actions within it.
--
Update
For strong_params, you have to remember what this is doing exactly.
Strong Params is just a method which allows you to send certain parameters to the model. This means if someone tries to mass-assign, it won't pass the un-permitted params through.
When you mention that I'm calling the model twice - I'm only calling it for different actions. The new action is there to create a new instance of the ActiveRecord object, the create action is there to save that instance (you have to recreate it with the params from your form)
You'll want to read up on strong params here
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
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])