How to use strong parameters in Rails 4? - ruby-on-rails

I am trying to upgrade my app from Rails 3 to Rails 4 and I can't seem to get the syntax right in line 12:
class ProjectsController < ApplicationController
before_filter :find_project
...
private
def find_project
#project = Project.find(params[:id])
end
def valid_people
if params[:project][:person_ids].present? # how to do this with strong parameters?
person_ids = params[:project][:person_ids].map(&:to_i)
valid_ids = current_user.people.pluck(:id)
redirect_to root_path if (person_ids - valid_ids).any?
end
end
def project_params
params.require(:project).permit(:name, :description, :person_ids)
end
end
I keep getting this error: Unpermitted parameters: person_ids
How can I use only the person_ids parameter?
Thanks for any help.

The idea of strong parameters is that you call the function you have defined to get your parameters
if params[:project][:person_ids].present? # how to do this with strong parameters?
would become
if project_params[:person_ids].present? # how to do this with strong parameters?
also i'm guessing :person_ids is an array if so replace your :person_ids with {:person_ids => []}

Related

Params is nil on entry into controller method

Rails 5.2
In my inventories_controller.rb, I have the following:
before_action :fetch_product, only: [:show]
def show
........
end
def fetch_product
if params.has_key?(:sku)
#product = Product.get_product(params)
end
end
This works fine, when I do: http://0.0.0.0:3000/sku/12345678
I am trying to implement search functionality, so I modified nventories_controller.rb as follows:
def fetch_product
if params.has_key?(:search) && !params[:search].blank?
product = Product.find_by_sku(params[:search])
if !product
params = params.except[:search]
redirect_to product_show_path, alert: 'Product was not found'
end
params = params.merge!(:sku, product.sku)
end
if params.has_key?(:sku)
#product = Product.get_product(params)
end
end
When I do: http://0.0.0.0:3000/sku/12345678
I get an instant error message:
undefined method `has_key?' for nil:NilClass
Using my debugger, I find that on entry into the fetch_product method, params is nil
Any idea what's going on?
params = params.merge!(:sku, product.sku) modifies the hash in place and returns nil, don't do that assignment, just call params.merge! (if you still want to do the assignment, remove the "!").
Personally, I wouldn't modify the params hash unless it's really really needed, I would use another variable.

rails 4.1 from rails 4 in action and rspec

I'm trying to learn rails 4.1 from rails 4 in action book, I've got to chapter 13, in this chapter defined API for JSON and XML.
It defined a controller like this :
class Api::V1::ProjectsController < Api::V1::BaseController
def index
respond_with(Project.for(current_user).all)
end
def create
project = Project.new project_params
if project.save
respond_with(project, :location => api_v1_project_path(project))
else
respond_with(errors: project.errors.messages)
end
end
private
def project_params
params.require(:project).permit(:name)
end
end
And a rspec test like this :
it "unsuccessful JSON" do
post "#{url}.json", :token => token, :project => {}
expect(last_response.status).to eql(422)
errors = {"errors" => { "name" => ["can't be blank"]}}.to_json
expect(last_response.body).to eql(errors)
end
when I run the test, I get these results :
ActionController::ParameterMissing: param is missing or the value is
empty: project
I know, it's because of strong parameters.
i solved issue like this but any one has a batter idea?
def project_params
if params[:project].nil?
params[:project] = {:name => ''}
end
params.require(:project).permit(:name)
end
it has resolved this problem in my case
params.require(:project).permit(:name, :description) if params[:project]
You can permit nested parameters as explained in strong parameters in github.
In your case, this is probably what you want:
params.permit(:project => [:name, :description])

Can't save record attributes to the database

class Contact < ActiveRecord::Base
attr_accessor :email
def initialize(data)
data.each { |k, v| send("#{k}=", v) }
end
end
In rails console
Contact.create!({"email"=>"foo#gmail.com"})
The record saved to the database has email as nil
Update:
The data is being passed in is JSON. I am getting all the data from the JSON and trying to save that into the database.
Did you try:
Contact.create!(email: "foo#gmail.com")
The email as a :symbol and no curly brackets?
Also, why are you initializing in your model?
With Mohamed El Mahallaway, I think your code setup could be improved (to negate initializing your model). I think you'll be better using the strong_params functionality of Rails:
#app/controllers/contacts_controller.rb
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
#contact.email = "foo#gmail.com"
#contact.save
end
private
def contact_params
params.require(:contact).permit(:email, :other, :params)
end
I may have miscalculated your competency with Rails, but this is the "Rails" way to save the correct data to your model :) You may to have a before_save method in your model to use the email attribute, considering it's a virtual attribute

ActionController::ParameterMissing (param not found: order) [duplicate]

This question already has answers here:
ActionController::ParameterMissing (param is missing or the value is empty: film):
(3 answers)
Closed 7 years ago.
I am trying to send a post request using the Postman chrome extension to my Ruby on Rails app, but i keep getting the error
ActionController::ParameterMissing (param not found: order):
app/controllers/orders_controller.rb:27:in order_params'
app/controllers/orders_controller.rb:20:in create
The code in my orders_controller is
class OrdersController < ApplicationController
protect_from_forgery :except => :create
def new
#order = Order.new
end
def index
#orders = Order.all
end
def show
#order = Order.find(params[:id])
end
def create
#order = Order.new(order_params)
render text: params[:product]
end
private
def order_params
params.require(:order).permit(:product)
end
end
My key Value pairs to the Postman extension are product[product_name] Samsung
For you to use params.require(:order). the incoming parameters should be something like {"order"=>...}
Check the documentation at http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html to use Strong Parameters,.
Based on your information about the key-value pairs used, there is no key called "order" in the incoming-data. That's the reason - its failing.
Hope, this helps
Probably the params method is requiring something that you don't have. Inspect the params.
This worked for me:
Controller:
def progress_params
params.require(:progress).permit(:game_id, :level_id)
end
View:
<%= link_to "Completed", progresses_path(:progress =>{:game_id => #level.game_id.to_i, :level_id => #level.id.to_i} ), :method => :post %>

How to remove a field from params[:something]

My registration form, which is a form for the Users model, takes a string value for company. However, I have just made a change such that users belongs_to companies. Therefore, I need to pass an object of Company to the Users model.
I want to use the string value from the form to obtain the an object of Company:
#user.company = Company.find_by_name(params[:company])
I believe the above works, however the form is passing the :company (which is string) into the model when I call:
#user = User.new(params[:user])
Therefore, I want to know (and cannot find how) to remove the :company param before passing it to the User model.
Rails 4/5 - edited answer
(see comments)
Since this question was written newer versions of Rails have added the extract! and except eg:
new_params = params.except[the one I wish to remove]
This is a safer way to 'grab' all the params you need into a copy WITHOUT destroying the original passed in params (which is NOT a good thing to do as it will make debugging and maintenance of your code very hard over time).
Or you could just pass directly without copying eg:
#person.update(params[:person].except(:admin))
The extract! (has the ! bang operator) will modify the original so use with more care!
Original Answer
You can remove a key/value pair from a Hash using Hash#delete:
params.delete :company
If it's contained in params[:user], then you'd use this:
params[:user].delete :company
You should probably be using hash.except
class MyController < ApplicationController
def explore_session_params
params[:explore_session].except(:account_id, :creator)
end
end
It accomplishes 2 things: allows you to exclude more than 1 key at a time, and doesn't modify the original hash.
The correct way to achieve this is using strong_params
class UsersController < ApplicationController
def create
#user = User.new(user_params)
end
private
def user_params
params.require(:user).permit(:name, :age)
end
end
This way you have more control over which params should be passed to model
respond_to do |format|
if params[:company].present?
format.html { redirect_to(:controller => :shopping, :action => :index) }
else
format.html
end
end
this will remove params from the url
Rails 5+: Use the handy extract! method with strong params!
The extract! method removes the desired variable from the Parameters object (docs) and returns a new ActionController::Parameters object. This allows you to handle params properly (i.e. with strong params) and deal with the extracted variable separately.
Example:
# Request { user: { company: 'a', name: 'b', age: 100 } }
# this line removes company from params
company = params.require(:user).extract!(:company)
# note: the value of the new variable `company` is { company: 'a' }
# since extract! returns an instance of ActionController::Parameters
# we permit :name and :age, and receive no errors or warnings since
# company has been removed from params
params.require(:user).permit(:name, :age)
# if desired, we could use the extracted variable as the question indicates
#company = Company.find_by_name(company.require(:company))
Full example in controller
Of course, we could wrap this up in a handy method in our controller:
class UsersController < ApplicationController
before_action :set_user, only: [:create]
def create
# ...
#user.save
end
def set_user
company = params.require(:user).extract!(:company)
#user = User.new(params.require(:user).permit(:name, :age))
#user.company = Company.find_by_name(company.require(:company))
end
end
To be possible to delete you can do a memo:
def parameters
#parameters ||= params.require(:root).permit(:foo, :bar)
end
Now you can do:
parameteres.delete(:bar)
parameters
=> <ActionController::Parameters {"foo" => "foo"} permitted: true>

Resources