I have a form that passes an array to my controller in the params and it keeps causing an ActiveModel::ForbiddenAttributesError. My create function calls out to another function to fix these array params and combine the parts into a string, but I think it's too late at that point.
Params
{ "remote"=>
{ "name"=>"",
"start_date"=>"9/27/2016",
"email"=>"",
"allergies"=>["Peanuts", "Soy Protein", "Dairy", ""],
}
}
Controller
def create
new_params = fix_params(params, ["allergies"])
remote_params = new_params["remote"]
#remote = Remote.new(remote_params)
respond_to do |format|
if #remote.save
format.html { redirect_to root_path, notice: 'Remote was successfully created.' }
format.json { render :show, status: :created, location: #remote }
else
format.html { render :new }
format.json { render json: #remote.errors, status: :unprocessable_entity }
end
end
end
def fix_params(params, fields)
fields.each do |field|
to_change = params[:remote][field]
new_param = to_change.join(", ").strip()
params[:remote][field] = new_param || ""
end
return params
end
Maybe there is a better way to pass these variables?
The error was occurring due to the fact that there were unpermitted parameters because I never explicitly stated that there will be array's passed in the params.
I modified my strong parameters to include params.require(:remote).permit(:name, :start_date, :email, :allergies => [])
Related
I have a model called Litter that accepts nested attributes for the model Puppy. When submitting an update to a litter I want to modify all the nested puppies so it adds a new attribute (breed_id). This is because the breed_id can be inferred from the litter and I don't want the user to specify it for every puppy. Here's what my controller looks like:
def update
litter_params[:puppies_attributes].each do |puppy|
puppy[1][:breed_id] = litter_params[:breed_id]
end
respond_to do |format|
if #litter.update(litter_params)
format.html { redirect_to litters_url, notice: "Litter was successfully updated." }
format.json { render :show, status: :ok, location: #litter }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #litter.errors, status: :unprocessable_entity }
end
end
end
However, for some reason the puppy nested attributes continue to not include the new attribute (breed_id):
Parameters: {"authenticity_token"=>"[FILTERED]", "litter"=>{"dog_ids"=>["", "3", "10"], "breed_id"=>"115", "puppies_attributes"=>{"0"=>{"_destroy"=>"false", "name"=>"Oscar", "id"=>"31"}, "1623432054943"=>{"_destroy"=>"false", "name"=>"James"}}}, "commit"=>"Update Litter", "id"=>"11"}
Any idea how I can add this attribute to the nested models?
This is my litter_params by the way:
def litter_params
params.require(:litter).permit(:breed_id, :breeder_id, dog_ids: [], puppies_attributes: [:_destroy, :id, :name])
end
I want to create multiples objects of a same model in Rails and I'm facing some problems saving them. I already add and remove fields dynamically, but I can't figure out how to save the multiples objects.
I'm receiving the data from my View like this:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"0aoRgalvZPKdBJr15EooxNCimh2C6R2RBYi3wTXTpaIwpzb8cNSAH/968932KFscg8eiNPej1x2iYFsaWalVQw==",
"transaction"=>{
"client_id"=>"206",
"invoice_id"=>"1",
"date"=>"07/07/2016",
"value"=>"50",
"description"=>""},
"dates"=>[
"07/08/2016",
"07/09/2016"],
"values"=>[
"49",
"48"],
"commit"=>"Save"}
transaction is the main transaction, dates and values are what difers from the main transaction and the other two transactions.
My create method in TransactionController is like this:
def create
#transaction = Transaction.new(transaction_params)
dates = params['dates']
values = params['values']
if(!dates.nil?)
#transactions_ = []
dates.length.times do |i|
t = Trasanction.create(
client_id: #transaction.client_id,
invoice_id: #transaction.invoice_id,
description: #transaction.description,
date: dates[i],
value: values[i])
#transactions_ << t
end
end
respond_to do |format|
if #transaction.save
#transactions_.each do |t|
t.save
end
format.html { redirect_to #transaction, notice: 'Transaction succefully created.' }
format.json { render :show, status: :created, location: #transaction }
else
format.html { render :new }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
But I'm getting this error:
uninitialized constant TransactionsController::Trasanction
t = Trasanction.create(
Apparently I can't call Transaction.create that way, but I'm almost sure I saw something like that on a tutorial.
I see there is a mistake in your class name. It should be
Transaction.create({})
but, you are referring to it as
Trasanction.create({})
Just change the class name and it should work.
I have an Audi model in my ruby on rails application in which there are many fields like model, variant, car image, exterior, interior, brochure etc. When I try to update some attributes(not all), then it gives undefined method `each' for nil:NilClass in exterior and interior image section.
More specifically, the issue is here:
params[:exterior_image].each { |exterior_image| ... }
update method:
def update
respond_to do |format|
#audi_model = AudiModel.find(params[:id])
if #audi_model.update(audi_model_params)
model_exterior_image_names = #audi_model.car_exterior_images.map{|m|m.exterior_image_file_name}
params[:exterior_image].each { |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
}
model_interior_image_names = #audi_model.car_interior_images.map{|m|m.interior_image_file_name}
params[:interior_image].each { |interior_image|
unless model_interior_image_names.include?(interior_image.original_filename)
#audi_model.car_interior_images.create(interior_image: interior_image)
end
}
format.html { redirect_to #audi_model, notice: 'Audi model was successfully updated.' }
format.json { render :show, status: :ok, location: #audi_model }
else
format.html { render :edit }
format.json { render json: #audi_model.errors, status: :unprocessable_entity }
end
end
Request
parameters :
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"3qiq/VNRNk369HEZr0Eb/R5iuhKgGTpJCfOh8ek3nGWLeU+zDNDvEAwJ3SvlLb0h4gVql549d3GnCV9Fa/ZnNA==",
"audi_model"=>{"car_model"=>"TT",
"variant"=>"Diesel",
"introduction"=>"test",
"engine"=>"test",
"video_url"=>"https://www.youtube.com/watch?v=N3x_RZlOmK0",
"brochure_url"=>"http://www.audigurgaon.in/brochure/tt-brochure-2014.pdf"},
"commit"=>"Update Audi model",
"id"=>"19"}
Your params doesn't have :exterior_image key, so it would return nil. You have to check to make sure there params[:exterior_image] is not nil and only then call .each method on it.
params[:exterior_image].each do |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
end if params[:exterior_image]
Alternatively, give it an empty array:
(params[:exterior_image] || []).each do |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
end
I am passing variable like that:
new_sub_request_path(request_id:#request.id)
so i get this url:
http://localhost:3000/sub_requests/new?request_id=1
In my controller i want to assign that request_id like that:
#sub_request = SubRequest.new(sub_request_params)
#sub_request.request_id = params[:request_id]
and my strong parameters are defined:
def sub_request_params
params.require(:sub_request).permit(:description, :diagnos, :price, :payment, :request_id)
end
But after save i have empty request_id attribute, so it seems that it is not assigned. What am I doing wrong?
EDIT:
Inspecting parameters in the console showed that i only have those attributes that are in my form.
EDIT2:
def create
#sub_request = SubRequest.new(sub_request_params)
#sub_request.request_id = params[:sub_request][:request_id]
respond_to do |format|
if #sub_request.save
format.html { redirect_to #sub_request, notice: 'Sub request was successfully created.' }
format.json { render :show, status: :created, location: #sub_request }
else
format.html { render :new }
format.json { render json: #sub_request.errors, status: :unprocessable_entity }
end
end
end
You have to define something like below for the request_id to save in sub_requests table.
In your create method add this line
#request = Request.find(params[:request_id]) and do
#sub_request.request_id = #request.id
or
You can just add a hidden_field in your form like below
<%= f.hidden_field :request_id, :value => #request.id %>
And make sure you are permitting :request_id in your sub_request_params
I have a session variable (user_id) that I'd like to include as a foreign key on a record the user is inserting. I have the form values all coming through the form submit to my controller's entity.update(params) method without a problem using the default params definition. That code looks like
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type, :profile_id)
end
The update method looks like
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
Now I'd like to append the :profile_id session variable to the #brand_params and following other threads here, I've tried a setter method:
def set_brand_params(key, val)
if #brand_params != nil
#brand_params[key] = val
end
end
However, calling this, #brand_params is always nil. Trying to directly add to the brand_params hash doesn't work because it's a better method. If there's a better way to meet this (I'd assume common) use case, I'm all ears! Otherwise, I'd like to know why the var is always nil though in this context, at least the brand_params method sees it as defined and with value. I got this solution in Adding a value to ActionController::Parameters on the server side
Here is the update method as requested:
def update
puts "update"
set_brand_params("profile_id", session[:prof])
respond_to do |format|
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
I'm not agree with merge your data with the params. Because you must permit only the fields you expect your user update. In this case you don't want the user update profile_id on brands, and that is a security best practice.
Then brand_params must be:
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type)
end
Your method update may look by this:
def update
#brand = Brand.find(params[:id])
#brand.assign_attributes(profile_id: session[:prof])
respond_to do |format|
if #barnd.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.'}
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
You don't need the method set_brand_params at all.
If this don't do the trick, please publish the entry controller, and I hope we find the issue.
edit: add respond_to.