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
Related
I have a model with movies and actors and I want both to be taggeable. I know there's a gem for that but I thought I'd teach myself polymorphic associations :)
Basic functionality works (I can do stuff like amovie.tags.create etc...) but now I want forms for movies and actors where tags can be selected and deselected.
Problem : I cannot deselect a tag:
While selecting a tag (that exists) works, when I deselect a tag, I get an error. Here's the relevant code:
Movie Form:
<%= form.collection_select(:tag_ids, Tag.order(:name), :id, :name, {}, { class: 'selectize-tag', multiple: true }) %>
movies controller - update section as well as movies_params private function:
def update
respond_to do |format|
if #movie.update(movie_params)
format.html { redirect_to #movie, notice: "Movie was successfully updated." }
format.json { render :show, status: :ok, location: #movie }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
def movie_params
params.require(:movie).permit(:title, :runtime, :country, :release_year, :sort_title, tag_ids: [])
end
Error I get:
Mysql2::Error: Column 'taggeable_id' cannot be null
Params - I think the problem is the line that has tag IDs and one of them is ""
{"_method"=>"patch",
"authenticity_token"=>"[FILTERED]",
"movie"=>
{"title"=>"The Avengers",
"sort_title"=>"Avengers",
"release_year"=>"2012",
"country"=>"US",
"runtime"=>"143",
"tag_ids"=>["", "3"]},
"commit"=>"Update Movie",
"id"=>"48"}
So not sure what I need to do for that empty tag id there to not be submitted but rather to trigger "remove tag with ID xyz from movie abc?
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 => [])
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 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.