Create then Update - Rails - ruby-on-rails

I have a set of parameters below that are submitted through a form
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pyMkh1eJ7WxYC978XKjdsyGOeGDvi6RTIOSGb9KMqkc=", "link"=>{"category_id"=>"1", "comment"=>"", "url"=>"yahoo.com "}, "type"=>"html", "original_url"=>"http://yahoo.com", "url"=>"http://www.yahoo.com/", "title"=>"Yahoo!", "description"=>"Welcome to Yahoo!, the world's most visited home page. Quickly find what you're searching for, get in touch with friends and stay in-the-know with the latest news and information.", "favicon_url"=>"http://www.yahoo.com/favicon.ico", "provider_url"=>"http://www.yahoo.com", "provider_display"=>"www.yahoo.com", "provider_name"=>"Yahoo", "safe"=>"true", "html"=>"", "thumbnail_url"=>"", "object_type"=>"link", "image_url"=>"", "category_id"=>"1"}
I want to create a new "links" record in the links model, which belongs to the categories model. My "create" action in the links controller looks like this
def create
#category = Category.find_by_id(params[:category_id])
#link = #category.links.build(params[:link])
#link.user_id = current_user.id
respond_to do |format|
if #link.save
links_attributes = params.slice(:original_url, :title, :description, :favicon_url, :provider_url, :provider_display, :thumbnail_url, :object_type)
#link.update_attributes(links_attributes)
else
end
end
end
If I just did #link.save without the update attributes, it only saves comment, url and category id. However, the above creates 2 records, one comment, url and category_id and another with all of the data.
How can I make sure this creates just one record, with all of the information?
UPDATE
If I could just create the record with the 3 parameters, then update it with the remaining parameters (links_attributes), I would be fine with that...just not sure how to do it.
This is the output I get when submitting:
Started POST "/categories/1/links" for 127.0.0.1 at 2013-01-11 12:43:44 -0500
Processing by LinksController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pyMkh1eJ7WxYC978XKjdsyGOeGDvi6RTIOSGb9KMqkc=", "link"=>{"category_id"=>"1", "comment"=>"", "url"=>"bloomberg.com "}, "type"=>"html", "original_url"=>"http://bloomberg.com", "url"=>"http://www.bloomberg.com/", "title"=>"Business, Financial & Economic News, Stock Quotes", "description"=>"Bloomberg is a premier site for business and financial market news. It delivers world economic news, stock futures, stock quotes, & personal finance advice.", "favicon_url"=>"http://www.bloomberg.com/favicon.ico", "provider_url"=>"http://www.bloomberg.com", "provider_display"=>"www.bloomberg.com", "provider_name"=>"Bloomberg", "safe"=>"true", "html"=>"", "thumbnail_url"=>"http://www.bloomberg.com/image/is2KySnyVWmA.jpg", "object_type"=>"link", "image_url"=>"", "category_id"=>"1"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "links" ("category_id", "comment", "created_at", "description", "favicon_url", "object_type", "original_url", "points", "profile_link", "provider_display", "provider_url", "thumbnail", "thumbnail_url", "title", "updated_at", "url", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["category_id", "1"], ["comment", ""], ["created_at", Fri, 11 Jan 2013 17:43:
Started POST "/categories/1/links" for 127.0.0.1 at 2013-01-11 12:43:44 -0500
Processing by LinksController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pyMkh1eJ7WxYC978XKjdsyGOeGDvi6RTIOSGb9KMqkc=", "link"=>{"category_id"=>"1", "comment"=>"", "url"=>""}, "commit"=>"Post", "category_id"=>"1"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
SQL (0.4ms) INSE44 UTC +00:00], ["description", "Bloomberg is a premier site for business and financial market news. It delivers world economic news, stock futures, stock quotes, & personal finance advice."], ["favicon_url", "http://www.bloomberg.com/favicon.ico"], ["object_type", "link"], ["original_url", "http://bloomberg.com"], ["points", nil], ["profile_link", nil], ["provider_display", "www.bloomberg.com"], ["provider_url", "http://www.bloomberg.com"], ["thumbnail", nil], ["thumbnail_url", "http://www.bloomberg.com/imRT INTO "links" ("category_id", "comment", "created_at", "description", "favicon_url", "object_type", "original_url", "points", "profile_link", "provider_display", "provider_url", "thumbnail", "thumbnail_url", "title", "updated_at", "url", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["category_id", "1"], ["comment", ""], ["created_at", Fri, 11 Jan 2013 17:43:44 UTC +00:00], ["description", nil], ["favicon_url", nil], ["object_type", nil], ["original_url", nil], ["points", nil], ["profile_link", nil], ["provider_display", nil], ["provider_url", nil], ["thumbnail", nil], ["thumbnail_url", nil], ["title", nil], ["updated_at", Fri, 11 Jan 2013 17:43:44 UTC +00:00], ["url", ""], ["user_id", 1]]
(1.1ms) commit transaction
Rendered links/create.js.erb (0.0ms)
Completed 200 OK in 8ms (Views: 3.9ms | ActiveRecord: 1.6ms)
age/is2KySnyVWmA.jpg"], ["title", "Business, Financial & Economic News, Stock Quotes"], ["updated_at", Fri, 11 Jan 2013 17:43:44 UTC +00:00], ["url", "bloomberg.com "], ["user_id", 1]]
(2.5ms) commit transaction
Rendered links/create.js.erb (0.0ms)
This is my form:
<%= form_for([#category, #category.links.build], :remote => true, :class => "form-horizontal") do |f| %>
<%= f.hidden_field :category_id, :value => params[:id] %>
Comment: <%= f.text_field :comment %><BR>
Link: <%= f.text_field :url %>
<%= f.submit "Post", :class => "btn", :disable_with => '...', :id => "new_link_button" %>
<% end %>
<div class="selector" style="width:350px;margin:-30px 0px 0px 0px;"></div>
<!-- Placeholder that tells Preview where to put the loading icon-->
<div class="loading">
<img src='http://embedly.github.com/jquery-preview/images/loading-rectangle.gif'>
</div>
<script>
$('#link_url').preview({ key:'60f1dcdf3258476794784148a6eb65e7', // Sign up for a key: http://embed.ly/pricing
selector : {type:'rich'},
preview : {
submit : function(e, data){
$.ajax({
dataType: 'script',
url: this.form.attr('action'),
type: 'POST',
data: data
});
},
},
autoplay : 0,
maxwidth : 350,
display : {display : 'rich'}
});
$('#new_link_button').click(function(e) {
e.preventdevault();
$('.new_link').submit();
return false;
});
</script>
This is my routes:
resources :categories, :only => [:new, :show, :create, :edit, :update] do
resources :links, :only => [:new, :show, :create, :edit, :update]
resources :industries, :only => [:new, :show, :create, :edit, :update]
resources :territories, :only => [:new, :show, :create, :edit, :update]
end

Try setting them before save.
def create
#link = Link.new(params[:link])
#link.category_id = params[:category_id]
#link.original_url = params[:original_url]
#link.title = params[:title]
#link.description = params[:description]
#link.user_id = current_user.id
# etc...
respond_to do |format|
if #link.save
# do things...
else
# do other things...
end
end
end

I think there's a problem with how your form is being constructed. As you can see in your posted parameters, params[:link] only includes a subset of the data you are trying to save on link:
"link"=>{"category_id"=>"1", "comment"=>"", "url"=>"yahoo.com "}
The rest is all at the top level of the params array:
Parameters: {... "original_url"=>"http://yahoo.com", "url"=>"http://www.yahoo.com/", "title"=>"Yahoo!", "description"=>"Welcome to Yahoo!..." ...}
You should look at how you're using form_for to construct your form, and make sure it's being used correctly for the additional parameters.
Edit:
If you can't edit the form, then you could do this in your controller:
#link.user_id = current_user.id
links_attributes = params.slice(:original_url, :title, :description, :favicon_url, :provider_url, :provider_display, :thumbnail_url, :object_type)
#link.attributes = links_attributes
respond_to do |format|
if #link.save
...

First of all, you don't need to call #link.save then #link.update_attributes, because #link.update_attributes would save #link in your db if it is not already there.
From the logs you posted, it seems your controller receives two post requests, this is why it creates two objects, I think the reason, is that two submits happen:
one by the form that is submitted and the other one by the ajax request inside your $('#link_url').preview(... code.

Related

accept_nested_attributes_for creates one extra nil record on Rails

I am using Rails as a backend and React as my front-end. On the React side, I am using fetch to do POST request to my model named schedule. I am also adding a child attributes for worker model.
Here are some code snippets that I have. I am using has_many :through relationship in rails.
My Rails models and controller:
//schedule.rb
has_many :workers, through: :rosters, dependent: :destroy
has_many :rosters, inverse_of: :schedule
//worker.rb
has_many :schedules, through: :rosters
has_many :rosters, inverse_of: :worker
//roster.rb
belongs_to :schedule
belongs_to :worker
//schedules_controller.rb
def create
#schedule = Schedule.new(schedule_params)
#workers = #schedule.rosters.build.build_worker
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
...
def schedule_params
params.permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])
end
On React side:
//inside Client.js
function postSchedule(date, cb) {
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1,
workers_attributes: [{name: "Iggy Test", phone: "123-456-7890"}, {name: "Iggy Test 2", phone: "987-654-3210"}]
})
}).then((response) => response.json())
.then(cb);
};
//inside main app:
postSchedule(){
Client.postSchedule(this.state.date, (schedule) => {
this.setState({schedules: this.state.schedules.concat([schedule])})
})
};
The problem that I have is, when I submit a new schedule, I expect to see a new schedule with two workers: "Iggy Test" and "Iggy Test 2". However, when I looked inside Rails, it is creating 3 workers: "Iggy Test", "Iggy Test 2", and nil.
Here is what is happening when I submit the request:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-24 09:55:16 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}, {"name"=>"Iggy Test 2", "phone"=>"987-654-3210"}], "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "use
r_id"=>1}}
Unpermitted parameter: schedule
(0.1ms) begin transaction
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["date", 20
17-05-27 02:00:00 UTC], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC], ["user_id", 1]
]
SQL (0.2ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test"], ["phone", "123-456-7890"], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 64], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.1ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test 2"], ["phone", "987-654-3210"], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.1ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 65], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2017-05-24 16:55:16 UTC
], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["sc
hedule_id", 57], ["worker_id", 66], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.7ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 60]]
SQL (0.1ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 61]]
(2.6ms) commit transaction
Completed 200 OK in 68ms (Views: 0.8ms | ActiveRecord: 5.6ms)
The log created a schedule, then a worker (Iggy Test), then a roster (for that schedule and Iggy Test), then another worker (Iggy Test 2), then another roster (for Iggy Test 2 and that schedule) - instead of stopping, it created another worker (nil) and a roster for that nil worker.
Why is it behaving such? How can I fix it to create only the specified workers?
As a side note - if you noticed, the log says unpermitted parameter: schedule. That message disappears when I add require(:schedule) inside my schedule_params, but it would instead create only one nil worker.
accepts_nested_attributes_for is not creating an extra record. You are.
def create
#schedule = Schedule.new(schedule_params)
# This adds a worker with no attributes
#workers = #schedule.rosters.build.build_worker
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
"Unpermitted parameter: schedule" is just a warning that there was a param is in the params hash that was not whitelisted by .permit. It is logged since it could be a malicious attempt to fish for mass assignment vulnerabilities.
.require takes a single key from the params hash and raises an error if it not present and is not what you want when you have a flat params hash.
Instead you should look into why the params sent by react include both the unwrapped params and I don't get why you are sending both the unwrapped params and a "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1} hash. I don't really know React but I'm guessing it has something to do with this.state.schedules.concat([schedule])

Rails 5 accepts_nested_attributes_for unpermitted parameter error? (React front end)

I have looked at previous SO solutions on accepts_nested_attributes here and here, but I am still getting the error. I am using React as front end and Rails back end. I am trying to create a request to be sent to schedules, and from there to populate to workers.
I am using Rails 5.0.2. I have a schedule, worker, roster models.
//Schedule
has_many :workers, through: :rosters, dependent: :destroy
has_many :rosters
accepts_nested_attributes_for :workers #implement accept_nested_attributes here
//Roster
belongs_to :schedule
belongs_to :worker
//Worker
has_many :schedules, through: :rosters
has_many :rosters
And here is my Schedule controller:
def create
#schedule = Schedule.new(schedule_params)
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
...
private
def schedule_params
params.permit(:date, :user_id, :workers_attributes => [:worker_id, :name, :phone])
end
Here is the error that I got:
app/controllers/schedules_controller.rb:13:in `create'
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 10:30:38 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>{"name"=>"Iggy Test", "phone"=>"1
23-456-7890"}, "schedule"=>{"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
Completed 500 Internal Server Error in 15ms (ActiveRecord: 0.0ms)
TypeError (no implicit conversion of Symbol into Integer):
app/controllers/schedules_controller.rb:13:in `create'
Why is my request shows Unpermitted parameter schedule? If I remove workers_attributes and only have params.permit(:date, :user_id), it works. I can't figure out why the error points to schedule. How can I make successful POST nested_attributes request to rails?
I am using fetch to do POST request from react side:
...
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1,
workers_attributes: {name: "Iggy Test", phone: "123-456-7890"}
})
EDIT:
After following answer from #gabrielhilal, I added require(): params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone]), and edited the fetch POST on React's end to have array of objects instead of plain objects: workers_attributes: [{name: "Iggy Test", phone: "123-456-7890"}]. It does not complain anymore, and it does register new schedule. However, new workers are all nil:
#Worker.last shows:
#<Worker id: 32, name: nil, phone: nil, created_at: "2017-05-23 19:36:09", updated_at: "2017-05-23 19:36:09">
Sorry, don't mean to create nested question, but does anyone know why it is nil?
EDIT 2:
I got it to work, sort of.
If I have
def create
#schedule = Schedule.new(schedule_params)
#workers = #schedule.rosters.build.build_worker
...
and
//schedule_params
params.permit(:date, :user_id, :workers_attributes => [:id, :name, :pho
ne])
I was able to have "Iggy Test" to display, but it immediately creates another nil worker.
Log:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:42:38 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
(0.1ms) begin transaction
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (1.1ms) INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC], ["user_id", 1]
]
SQL (0.2ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test"], ["phone", "123-456-7890"], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 56], ["c
reated_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.1ms) INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2017-05-24 03:42:38 UTC
], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.6ms) INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["sc
hedule_id", 52], ["worker_id", 57], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.4ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 52],
["updated_at", 2017-05-24 03:42:38 UTC], ["id", 52]]
(5.6ms) commit transaction
Completed 200 OK in 417ms (Views: 6.9ms | ActiveRecord: 14.7ms)
If I modified params to have require(:schedule)
params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])
It creates a nil worker only.
Log:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:45:03 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
   (0.1ms)  begin transaction
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.4ms)  INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC], ["user_id", 1]
]
  SQL (0.2ms)  INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2017-05-24 03:45:03 UTC
], ["updated_at", 2017-05-24 03:45:03 UTC]]
  SQL (0.3ms)  INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sc
hedule_id", 53], ["worker_id", 58], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC]]
   (2.4ms)  commit transaction
Completed 200 OK in 81ms (Views: 1.3ms | ActiveRecord: 8.3ms)
Your post:
{
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1,
"workers_attributes"=>{
"name"=>"Iggy Test",
"phone"=>"123-456-7890"
},
"schedule"=> {
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1
}
}
You have two issues:
schedule is not permitted (that's why you see the message in the logs), but it will be just ignored anyway (won't raise any error).
the workers_attributes should be a collection of workers and not a simple hash, so that's why you are having the error.
You should get something like the following in the post request:
{
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1,
"workers_attributes"=>{
"0" => {
"name"=>"Iggy Test",
"phone"=>"123-456-7890"
}
}
}

Trouble splitting output of multiselect in Rails

I have a multiselect (using bootstrap-multiselect) in my #minisets new form that aims to associate #scales with the #miniset via the #sizes table.
The associations work fine. What I'm stuck on is how to loop through the multiple :scale_id submissions from the multiselect and create lines in the #sizes table for them all.
Following this answer I have been trying to use split and then loop the create but I think the fact that that answer pertains to a HABTM relationship and mine is has_many_through means I need a different solution?
In my minisets controller I have
def new
#miniset = Miniset.new
#miniset.sizes.build
end
def create
#miniset = Miniset.new(miniset_params)
if #miniset.save
params[:scale_id].split(',').each do |id|
#miniset.sizes.create(params[:sizes_attributes])
end
redirect_to #miniset
else
render 'new'
end
end
private
def miniset_params
params.require(:miniset).permit(:name, :release_date, :material, :pcode, :notes, :quantity, :random, productions_attributes: [:id, :manufacturer_id, :miniset_id], sizes_attributes: [:id, :scale_id, :miniset_id], sculptings_attributes: [:id, :sculptor_id, :miniset_id])
end
end
In my view I have
<%= f.fields_for :sizes do |size_fields| %>
<%= size_fields.label :scale_id, simple_pluralize(#miniset.scales.count, 'Scale') %>
<%= size_fields.select :scale_id,
options_from_collection_for_select(Scale.all, :id, :name, #miniset.scales.map(&:id)),
{},
{class: 'multiselect', multiple: true} %>
<% end %>
<script type="text/javascript">
$(document).ready(function() {
$('.multiselect').multiselect();
});
</script>
I'm currently getting error undefined methodsplit' for nil:NilClass` when I submit.
I think that may be because the log shows an empty scale_id passed before the two filled ones and split won't accept nil? Here is the log when submitting TWO scales.
Started POST "/minisets" for 127.0.0.1 at 2014-01-30 10:49:59 +0000
Processing by MinisetsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R0RxDMwB5/ytSb5qgjIlVR5as0/DTkstgFMDXcefDnc=", "miniset"=>{"name"=>"Test for size", "quantity"=>"10", "random"=>"0", "material"=>"Hard Plastic", "sizes_attributes"=>{"0"=>{"scale_id"=>["", "1", "5"]}}, "pcode"=>"", "release_date(1i)"=>"", "release_date(2i)"=>"", "release_date(3i)"=>"", "notes"=>""}, "Set Scale"=>{"#<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Size:0x007fcf643c29f0>"=>""}, "commit"=>"Add set"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'd59f28d384d62b71719dd845b4e5353cdd993016' LIMIT 1
Unpermitted parameters: scale_id
SQL (0.9ms) INSERT INTO "minisets" ("created_at", "material", "name", "notes", "pcode", "quantity", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["created_at", Thu, 30 Jan 2014 10:49:59 UTC +00:00], ["material", "Hard Plastic"], ["name", "Test For Size"], ["notes", ""], ["pcode", ""], ["quantity", 10], ["updated_at", Thu, 30 Jan 2014 10:49:59 UTC +00:00]]
SQL (0.6ms) INSERT INTO "sizes" ("created_at", "miniset_id", "updated_at") VALUES (?, ?, ?) [["created_at", Thu, 30 Jan 2014 10:49:59 UTC +00:00], ["miniset_id", 41], ["updated_at", Thu, 30 Jan 2014 10:49:59 UTC +00:00]]
(4.2ms) commit transaction
Completed 500 Internal Server Error in 153ms
NoMethodError (undefined method `split' for nil:NilClass):
app/controllers/minisets_controller.rb:19:in `create'
I'm sure what I have after the split is incorrect but I can't play with it until the split works. I can get rid of the error by adding to_s before the split but I get no better results.
Been making very slow progress on this multiselect for days now so any help very much appreciated.
Thanks to this fantastic youtube video I solved my problem.
My form:
<%= f.fields_for(#size) do |sf| %>
<%= sf.label simple_pluralize(#miniset.scales.count, 'Scale') %>
<%= collection_select( :scales, :id, #all_scales, :id, :name,
{},
{class: 'multiselect', multiple: true}) %>
<% end %>
In my minisets_controller I have the following new and create actions:
def new
#miniset = Miniset.new
#all_scales = Scale.all
#size = #miniset.sizes.build
end
def create
#miniset = Miniset.new(miniset_params)
params[:scales][:id].each do |scale|
if !scale.empty?
#miniset.sizes.build(:scale_id => scale)
end
end
if #miniset.save
redirect_to #miniset
else
render 'new'
end
end
It works perfectly. If anyone else is having the same problem, trying to get multiselects to work in rails with has_many_through, I recommend watching that video. So pleased.

Checkbox parameters submits but does not INSERT

In my Users table I have boolean columns: owner, manager.
The below does not update the table once the form is submitted.
<%= f.check_box :owner %>
<%= f.label :owner %>
Logs:
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"k0m814s9fRjCUZxeBXn5GO3o5Fq0evZG1Xc7IfUCOYU=", "user"=>{"name"=>"Bob Dylan", "email"=>"bob.dylan#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "manager"=>"0", "owner"=>"1"}, "commit"=>"Create my account"}
Unpermitted parameters: manager, owner
(0.2ms) begin transaction
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('bob.dylan#gmail.com') LIMIT 1
Binary data inserted for `string` type on column `password_digest`
SQL (56.3ms) INSERT INTO "users" ("created_at", "email", "name", "password_digest", "remember_token", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Thu, 06 Jun 2013 14:57:53 UTC +00:00], ["email", "bob.dylan#gmail.com"], ["name", "Bob Dylan"], ["password_digest", "$2a$10$t5hux4e.jDWS9GH7fJj7Z.gSkLehpJxzfwXOTqbnL6LA7zWZT/11S"], ["remember_token", "J-OFaVfx3a4KMGQ0Q9vttg"], ["updated_at", Thu, 06 Jun 2013 14:57:53 UTC +00:00]]
In your User controller you must have something like:
def user_params
params.require(:user).permit(:manager, :owner)
end
<label>Owner: </label><input type="checkbox" name="owner" value="1" />
The owner key will be present in the post array if the checkbox is checked.
To make the checkbox checked when viewing the form after the form is submitted, you need to add checked="checked" as an attribute on the checkbox element.
You will need to go into your view and create either a checkbox or a radio button for that particular field. In your view, you would do:
form_for #user do |f|
f.label :owner
f.check_box :owner
f.submit
end
You would wrap this in the html code as needed.

undefined method 'title'

I'm getting an error on the show action when new guidelines are being added to my app. This is since I changed the show action to allow for custom routes...The new guideline is added to the database correctly...
My show action in guidelines_controller.rb is
def show
#guideline = Guideline.where(title: params[:title]).first
respond_to do |format|
format.html # show.html.erb
format.json { render json: #guideline }
end
end
model guidelines.rb is
attr_accessible :content, :hospital, :title, :user_id, :guideline_id, :specialty
show view is
<p>Title: <%= link_to #guideline.title, seeguideline_path(#guideline.title) %> </p
Error message is
console says...
Started POST "/guidelines" for 127.0.0.1 at 2013-02-22 17:07:29 +1100
Processing by GuidelinesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"bQKIkSb4Wzr46FERMbU82Q1qMzd3GrGNq6Nqmr0KNhY=", "guideline"=>{"title"=>"Stackoverflo", "specialty"=>"Dermatology", "hospital"=>"Stack Hospital", "content"=>"www.stackoverflow.com"}, "commit"=>"Create Guideline"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 11 LIMIT 1
(0.1ms) begin transaction
Guideline Exists (0.4ms) SELECT 1 AS one FROM "guidelines" WHERE (LOWER("guidelines"."hospital") = LOWER('Stack Hospital') AND "guidelines"."title" = 'Stackoverflo') LIMIT 1
SQL (65.0ms) INSERT INTO "guidelines" ("content", "created_at", "hospital", "specialty", "subtitle", "title", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["content", "www.stackoverflow.com"], ["created_at", Fri, 22 Feb 2013 06:07:29 UTC +00:00], ["hospital", "Stack Hospital"], ["specialty", "Dermatology"], ["subtitle", nil], ["title", "Stackoverflo"], ["updated_at", Fri, 22 Feb 2013 06:07:29 UTC +00:00], ["user_id", 11]]
SOLR Request (152.5ms) [ path=#<RSolr::Client:0x007f9c79f2fc48> parameters={data: <?xml version="1.0" encoding="UTF-8"?><add><doc><field name="id">Guideline 35</field><field name="type">Guideline</field><field name="type">ActiveRecord::Base</field><field name="class_name">Guideline</field><field name="title_text">Stackoverflo</field></doc></add>, headers: {"Content-Type"=>"text/xml"}, method: post, params: {:wt=>:ruby}, query: wt=ruby, path: update, uri: http://localhost:8982/solr/update?wt=ruby, open_timeout: , read_timeout: } ]
(3.7ms) commit transaction
Redirected to http://localhost:3000/guidelines/35
SOLR Request (100.3ms) [ path=#<RSolr::Client:0x007f9c79f2fc48> parameters={data: <?xml version="1.0" encoding="UTF-8"?><commit/>, headers: {"Content-Type"=>"text/xml"}, method: post, params: {:wt=>:ruby}, query: wt=ruby, path: update, uri: http://localhost:8982/solr/update?wt=ruby, open_timeout: , read_timeout: } ]
Completed 302 Found in 485ms (ActiveRecord: 69.8ms)
Started GET "/guidelines/35" for 127.0.0.1 at 2013-02-22 17:07:30 +1100
Processing by GuidelinesController#show as HTML
Parameters: {"id"=>"35"}
Guideline Load (0.2ms) SELECT "guidelines".* FROM "guidelines" WHERE "guidelines"."id" = ? LIMIT 1 [["id", "35"]]
Guideline Load (0.2ms) SELECT "guidelines".* FROM "guidelines" WHERE "guidelines"."title" IS NULL LIMIT 1
Rendered guidelines/show.html.erb within layouts/application (18.3ms)
Completed 500 Internal Server Error in 83ms
ActionView::Template::Error (undefined method `title' for nil:NilClass):
6:
7: <div class="guideline span10">
8:
9: <p>Title: <%= link_to #guideline.title, seeguideline_path(#guideline.title) %> </p>
10: <strong> <a href="<%= #guideline.content %>", target = '_blank'>Link to guideline</a> </strong>
11: <p>Hospital Name: <%= #guideline.hospital %></p>
12:
app/views/guidelines/show.html.erb:9:in `_app_views_guidelines_show_html_erb__4234346501713687788_70155056040280'
app/controllers/guidelines_controller.rb:132:in `show'
route is
get '/:title', to: 'guidelines#show', as: :seeguideline
Are you sure your route is passing the :title param? What does your console log show for the SQL request for the query? I have a feeling your route isn't passing what you think it's passing...
Also, you're going to want to handle the case that the query comes back empty anyway. Having the app blow up probably isn't what you want.

Resources