In my rails controller, in a pry session, my params hash is nil. request.params has the expected hash.
If I comment out the params = … line, params returns to normal.
class UsersController < Clearance::UsersController
skip_before_filter :verify_authenticity_token
def update
binding.pry
params = params.require(:user).allow(:foo)
end
end
What could be causing this?
To begin with, params is a method. http://api.rubyonrails.org/classes/ActionController/StrongParameters.html#method-i-params
In your code, when you write
params = params.require(:user).allow(:foo)
you initialize a variable called params.
When you hit your pry, you have already initialized (gets initialized upon loading of code) but not yet set the value of your variable, params. Therefore, when you call it within your pry, it is set to nil. The method params is overwritten by your variable within the scope of your update method.
The params hash is what you get when the user request the page. For example:
https://www.example.com/index.html?username=john&email=john#example.com
The params hash would be
{username: 'john', email: 'john#example.com'}
And you can assess then like params[:username].
Looks like you are trying to use strong parameters to set what the user can or cannot update. In that case, what you should do is
def update
user = User.find(params[:id])
user.update_attributes(params.require(:user).permit(:foo))
end
This will only allow the user to update the foo attribute and nothing else.
Because this is so common, it is standard to write a private method called user_params and just call that method when you call save.
def update
user = User.find(params[:id])
user.update_attributes(user_params)
end
private
def user_params
params.require(:user).permit(:foo)
end
Related
I have many controllers where I set variables so that the appropriate views gain visibility to these variables. For example,
class UsersController < ApplicationController
...
def index
#users = User.all
end
...
This works. So how come this doesn't work:
class PlacesController < ApplicationController
...
def show
#params = params
end
...
If I byebug in the show-method, I can access params. If I byebug in the view (places/show.html.erb), then "params" and "#params" return nil.
Does this have something to do with the fact that "User" is an ActiveRecord and "Place" is not? How can I make arbitrary data accessible to the view?
You can use your controller instance variable #params in your /places views. But because you did not pass any params, params returns nil.
So, if this variables was out visibility, you would get NameError.
Try to set #params directly like #params = { foo: "bar" } and you will see it.
More about params in Rails here (#4 Parameters).
I have a serious problem with strong parameters. Its working pretty well in my about 200 actions but in one it doesn't because I'm working very dynamic with the parameters there and I also cant change it because of the applications design.
So I want to disable strong parameters validation in just this specific action. Is there a way to do this?
Strong parameters overrides the params method in ActionController::Base. You can simply override it and set it back to what you want yourself.
So this:
class MyController < ApplicationController
def params
request.parameters
end
end
Will effectively disable strong parameters for all actions in your controller. You only wanted to disable it for a particular action though so you could do that with:
class MyController < ApplicationController
before_action :use_unsafe_params, only: [:particular_action]
def params
#_dangerous_params || super
end
def particular_action
# My params is unsafe
end
def normal_action
# my params is safe
end
private
def use_unsafe_params
#_dangerous_params = request.parameters
end
end
Not too sure if this is best practice but for Rails 5 I just use request.params instead of params anytime I want to skip strong params.
So instead of something like:
post = Post.new(params[:post])
I use:
post = Post.new(request.params[:post])
You can use .permit! to whitelist any keys in a hash.
params.require(:something).permit!
However this should be treated as an extreme code smell and a security risk.
Nested hashes can be whitelisted with this trick:
params.require(:product).permit(:name, data: params[:product][:data].try(:keys))
I am new to ROR.
I have a controller
class Controllername < application
def method1
#obj = API_CALL
redirect_to redirect_url #calls the API authorization end point
#and redirects to action method2
end
def method2 #redirection to this action
#obj.somemethod #this value is null
end
end
My problem is when I use Instance variable or class varaible #obj or ##obj becomes nil in the action method2. I want this value to be whatever the value in method1.
Note: SESSION note helping as it's giving SSL error.
Any help is kindly appreciated.
Of cause using an instance variable doesn't work because the instance of the class only exists inside the method1 or method2 method .
What you can do is using class variables. You can set them using class_variable_set(:##class_variable_name, value) and get them using class_variable_get(::##class_variable_name) again. In your case it whould look like this:
class Controllername < application
def method1
class_variable_set(:##api_call_data, API_CALL)
redirect_to redirect_url #calls the API authorization end point
#and redirects to action method2
end
def method2 #redirection to this action
class_variable_get(:##api_call_data).somemethod #this value is null
end
end
Of cause this only works if the data is the same to every user if the data is user specific you need to use a class variable name that is user specific.
Once in a while we send customized registration links to our leads. The link contains parameters than can be used to pre-fill the registration form.
http://www.example.com/users/sign_up?user[company_name]=Foo&user[region]=NA
Our registration form has fields for accepting company name and region. Which can be pre-filled based on the registration link.
This should work in practice, but it doesn't due to how the registrations#new action is implemented. The new action calls the build_resource method with an empty hash.
def new
resource = build_resource({})
respond_with resource
end
The build_resource method ignores the resource_params when the input is non nil.
def build_resource(hash=nil)
hash ||= resource_params || {}
self.resource = resource_class.new_with_session(hash, session)
end
I had to over-ride the the new action in my registrations controller to overcome this issue. I don't like my solution as it is brittle.
def new
resource = build_resource
respond_with resource
end
Is there a reason why the new action is invoked with an empty hash? Can it be invoked with out empty hash(like in the create action)?
I ended up overriding build_resource and scoping the change to new action.
def build_resource(hash=nil)
# scope the change to new actions
return super unless action_name == "new"
super.tap do |user|
user.company_name = params[:user][:company_name]
user.region = params[:user][:region]
end
end
I believe this is the intended behaviour of the build_resource method. Similar to Model.new you can either pass a hash of initializing properties or nothing, resulting in a pre-filled and an empty model respectively.
If you want to make your controller action more explicit you could instead call build_resource(params[:user]) which should avoid the brittleness you're concerned about.
I'm using the facebooker gem which creates a variable called facebook_session in the controller scope (meaning when I can call facebook_session.user.name from the userscontroller section its okay). However when I'm rewriting the full_name function (located in my model) i can't access the facebook_session variable.
You'll have to pass the value into your model at some point, then store it if you need to access it regularly.
Models aren't allowed to pull data from controllers -- it would break things in console view, unit testing and in a few other situations.
The simplest answer is something like this:
class User
attr_accessor :facebook_name
before_create :update_full_name
def calculated_full_name
facebook_name || "not sure"
end
def update_full_name
full_name ||= calculated_full_name
end
end
class UsersController
def create
#user = User.new params[:user]
#user.facebook_name = facebook_session.user.name
#user.save
end
end