Deletion of nested attributes does not work - ruby-on-rails

I seem to be unable to delete items using the accepts_nested_attributes_for command but I have done this according to this tutorial and the associated git repo. My models are ...
class Job < ActiveRecord::Base
has_many :specialties, :inverse_of => :job
accepts_nested_attributes_for :specialties, allow_destroy: true, :reject_if => :all_blank
end
class Specialty < ActiveRecord::Base
belongs_to :job, :inverse_of => :specialties
end
In my Job form, I have...
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Specialty" %>
When I click the checkbox to delete the a couple of specialties, nothing happens. I checked the server output and received:
Started PATCH "/jobs/1" for 127.0.0.1 at 2013-07-16 16:15:16 -0400
Processing by JobsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8VxYXujcKXpLEm8+7B43SLU6X3fH00kIOmFK+nvaBKs=", "job"=>{"name"=>"Cook", "description"=>"Makes the food.", "specialties_attributes"=>{"2"=>{"name"=>"", "description"=>"", "_destroy"=>"1", "id"=>"3"}, "3"=>{"name"=>"", "description"=>"", "_destroy"=>"1", "id"=>"4"}}}, "commit"=>"Update Job", "id"=>"1"}
Job Load (0.1ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."id" = ? LIMIT 1 [["id", "1"]]
Unpermitted parameters: _destroy
Unpermitted parameters: _destroy
Unpermitted parameters: _destroy
Unpermitted parameters: _destroy
What did I miss? I've gone through the tutorial and repo a bunch of times and I can't see where I've gone off.

That's because of strong_parameters. You now have to permit keys. In your action:
params.permit(:_destroy)

I like #Damien Roche's answer but its just for not confusion to any one. follow this
In job_controller.rb
private
def job_params
params.require(:job).permit(:id, :description, :specialty_fields_attributes => [:id, :job_id, :avatar, :_destroy])
end

Related

Creating a Nested Association with Has_Many :Through

I am not sure if my title is properly using the vocabulary. I found a few SO posts where people had similar issues (I couldn't find a solution in those posts), so I used a similar title to those. I am trying to allow users to create clubs and automatically assign the user as a member of the club. However, it seems like I have something out of order when I tried to create the club.
I have three models:
###Models###
#user
has_many :club_memberships, :class_name => 'ClubMembership', :foreign_key => :member_id, :primary_key => :id
has_many :clubs, :through => :club_memberships
#club
attr_accessor :club_name, :club_type
has_many :club_memberships
has_many :members, :through => :club_memberships
#clubmembership
attr_accessor :club_id, :member_id, :membership_type
belongs_to :club
belongs_to :member, :class_name => "User", :foreign_key => :member_id, :primary_key => :id
Here are the relevant parts of the controllers
###Controllers###
#Clubs
def new
#club = Club.new
end
def create
#club = Club.new(club_params)
if #club.save
#club_membership = ClubMembership.create(
member_id: current_user.id,
club_id: #club.id,
membership_type: 'founder'
)
flash[:success] = "Club Created!"
redirect_to root_url
else
render #club.errors.full_messages
end
end
private
def club_params
params.require(:club).permit(:club_name, :club_type)
end
#ClubMemberships
def create
#club_membership = ClubMembership.new(club_membership_params)
if #club_membership.save
render #club_membership
else
render #club_membership.errors.full_messages
end
end
private
def club_membership_params
params.require(:club_membership).permit(:member_id, :club_id, :membership_type)
end
My form_for
###View###
#club#new
= form_for(#club) do |f|
.field.center-align
= f.label :club_name
= f.text_field :club_name, :class => "form-control fieldbox", autofocus: true
.field.center-align
= f.label :club_type
= f.text_field :club_type, :class => 'form-control fieldbox', autofocus: true
.actions.center-align
= f.submit "Create Club!", :class => "btn hoverable padtop"
And finally, here is what the log shows on post
#log
Started POST "/clubs" for at 2015-09-03 22:32:41 +0000
Cannot render console from ! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by ClubsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Ar2dv41/Tqk9EVjwfLLeD8bnpLoVWQIdDxG3Ju1GO3stLLvPd/FFgoFF9YuHobWbgb2byqkgAMiWRJAg5YcGKQ==", "club"=>{"club_name"=>"Test Club", "club_type"=>"Test Type"}, "commit"=>"Create Club!"}
(0.2ms) BEGIN
Club Exists (0.4ms) SELECT 1 AS one FROM `clubs` WHERE `clubs`.`club_name` = BINARY 'Test Club' LIMIT 1
SQL (0.3ms) INSERT INTO `clubs` (`created_at`, `updated_at`) VALUES ('2015-09-03 22:32:41', '2015-09-03 22:32:41')
(3.4ms) COMMIT
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 56 LIMIT 1
(0.1ms) BEGIN
ClubMembership Exists (0.3ms) SELECT 1 AS one FROM `club_memberships` WHERE (`club_memberships`.`member_id` = BINARY 56 AND `club_memberships`.`club_id` IS NULL) LIMIT 1
SQL (1.6ms) INSERT INTO `club_memberships` (`created_at`, `updated_at`) VALUES ('2015-09-03 22:32:41', '2015-09-03 22:32:41')
(3.1ms) COMMIT
Redirected to c9
Completed 302 Found in 71ms (ActiveRecord: 11.1ms)
I'll be honest. I have no clue what is happening in that POST or where to tackle this from next. It seems like the parameters I want are going through, but then they aren't. Any help would be appreciated.
I figured it out. I tried two things at once and it worked, so I can't say for sure what helped, but I am pretty sure the second thing was most important.
First, I removed the attr_accessor from both model's (Club and ClubMembership). Why did I put it in there in the first place? No idea. I probably saw it somewhere and thought it was cool.
Second, also in the models, I had validators that I didn't post because I didn't think they were important. I had:
validates :club_name, :club_type, :presence => true
validates :club_name, :uniqueness => true
I changed this to:
validates :club_name, presence: true
validates :club_type, presence: true
Turns out that was important and everything is working fine now.

Unpermitted parameters in a simple scaffold

I have 2 models Post and Photo:
class Post < ActiveRecord::Base
has_many :photos
end
and :
class Photo < ActiveRecord::Base
belongs_to :post
has_attached_file :photo,styles:{medium:"300x300>", small:"100x100>"}
validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/
validates :photo, presence: true
end
I made a single change to photos_controller so photos could be uploaded, I added :photo:
def photo_params
params.require(:photo).permit(:post_id, :photo)
end
But when I want to add a new photo I get this warning in log:
Unpermitted parameters: post
And here is the parameters:
Processing by PhotosController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gSiLdGHe3VM8Ka6gjTKk7xjcK0omPdvqfQ0DRRXdOKo=",
"photo"=>{"post"=>"1"}, "commit"=>"Update Photo", "id"=>"1"}
Note: I have a photo attribute in my Photo model but I think thats not going to make any problems and I'm using paperclip gem for uploading images.
From what I see in the parameters sent to the server, post (not post_id) is set to 1.
Rails tells you that you're trying to assign post, an unpermitted parameter, to 1 (while you only permitted post_id in your photo_params method).

Create join model record with accepts_nested_attributes_for

I have following models
class User < ActiveRecord::Base
has_many :project_users, dependent: :destroy
has_many :projects, through: :project_users
end
class ProjectUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
has_many :participants
has_many :tasks, through: :participants
end
class Task < ActiveRecord::Base
belongs_to :project
has_many :participants
has_many :project_users, through: :participants
accepts_nested_attributes_for :participants
end
class Participant < ActiveRecord::Base
belongs_to :project_user
belongs_to :task
end
So the flow should go like this:
1. User creates the project
2. User adds users to project via the join model ProjectUser
3. User creates a task for the project and selects those users from ProjectUsers, who will participate in the task. So I put an accepts_nested_attributes_for method and tried to build the nested form.
In my controller:
def new
#task = Task.new
#task.participants.build
end
def task_params
params.require(:task).permit(:project_id, :project_phase_id, :priority_id, :title, :due_date, :estimation, :responsible_id, :description, :participant_ids => [])#, :participants_attributes => [:project_user_id, :task_id])
end
participants_attributes is commented
In my view:
= f.association :participants, as: :select
Actual HTML generated:
<input name="task[participant_ids][]" type="hidden" value="">
<select class="select optional form-control" id="task_participant_ids" multiple="multiple" name="task[participant_ids][]">
<option value="57">AlexandeR MazeiN</option>
<option value="59">Firenze</option>
<option value="58">Vasily Strekotkin</option>
</select>
I add options via ajax, value = ProjectUser.id
I Have to do it like so, because I dont know which ProjectUsers there will be unless a concrete project for a task is selected.
Error I am getting:
Started POST "/tasks" for 127.0.0.1 at 2014-04-11 13:18:24 +0300
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
Processing by TasksController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"aXuk9ZuDvFZce+sbIQLRhWZlVjitMvySaJ7CwWfdmaQ=", "task"=>{"project_id"=>"20", "priority_id"=>"4", "project_phase_id"=>"40", "title"=>"Skepta", "due_date"=>"", "estimation"=>"8", "responsible_id"=>"6", "participant_ids"=>["", "57", "58"], "description"=>""}, "commit"=>"Create Task"}
Team Load (0.4ms) SELECT "teams".* FROM "teams" WHERE "teams"."id" = $1 LIMIT 1 [["id", 3]]
Participant Load (0.5ms) SELECT "participants".* FROM "participants" WHERE "participants"."id" IN (57, 58)
Completed 404 Not Found in 7ms
ActiveRecord::RecordNotFound - Couldn't find all Participants with IDs (57, 58) (found 0 results, but was looking for 2):
Your param hash has the IDs from ProjectUser as participant_ids, so when it queries the database it is looking for Participant models with these IDs. You need to set these as project_user_id inside of a list of participants, something like this:
participants: [ { project_user_id: 57 }, { project_user_id: 58 } ]
I'm not super familiar with build, but something along these lines should allow AR to properly construct the associations.

Controller not passing in values from the from to the create method

My Create controller passes in the for the child of a nested resource as null instead of passing the values i've just inputed into the form.
Here is my code
Routes:
resources :trips do
resources :pilgrims
end
Models:
Trip:
class Trip < ActiveRecord::Base
has_many :pilgrims
accepts_nested_attributes_for :pilgrims, :allow_destroy => true
attr_accessible :end_date, :leader_id, :name, :start_date, :pilgrim_attributes
end
Pilgrim:
class Pilgrim < ActiveRecord::Base
belongs_to :trip
attr_accessible :pilgrim_id, :surname, :name, :middle, :aka, :prefix, :address, :city, :state, :zip, :email, :telephone, :nationality, :date_of_birth, :passport_number, :expiration, :jordan, :room, :price, :status, :trip_id
end
My Pilgrim controller:
def new
#trip = Trip.find(params[:trip_id])
#pilgrim = Pilgrim.new
end
def create
#trip = Trip.find(params[:trip_id])
#pilgrim = #trip.pilgrims.build(params[:pilgrim])
if #pilgrim.save
flash[:notice] = "The <b>#{ #pilgrim.name }</b> has been created successfully."
redirect_to(trip_pilgrims_path, :notice => "The <b>#{ #pilgrim.name }</b> ship has been saved successfully.")
else
render(:new, :error => #pilgrim.errors)
end
end
Link to a gist with my form code Form
The routes seem to be correct, when i click on new_trip_pilgrim_path(#trip) it does point to trips/:trip_id/pilgrims/new and loads the new pilgrim form.
However when i click save on the form it redirects me to the route trips/3/pilgrims but shows the new pilgrim form saying all required fields were left blank.
This is what displays in the log.
Started POST "/trips/3/pilgrims" for 127.0.0.1 at 2013-01-19 22:12:06 -0800
Processing by PilgrimsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kOE06m3DNax43BOLYZ6t1lS7/T4wOWb2xM8m/mlQzvA=", "commit"=>"Create Pilgrim", "trip_id"=>"3"}
Trip Load (0.3ms) SELECT `trips`.* FROM `trips` WHERE `trips`.`id` = 3 LIMIT 1
(0.2ms) BEGIN
(0.2ms) ROLLBACK
Pilgrim Load (0.4ms) SELECT `pilgrims`.* FROM `pilgrims` WHERE `pilgrims`.`trip_id` = 3
Rendered pilgrims/_form.html.erb (36.4ms)
Rendered pilgrims/new.html.erb within layouts/application (37.2ms)
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
Trip Load (0.3ms) SELECT `trips`.* FROM `trips`
Completed 200 OK in 244ms (Views: 102.5ms | ActiveRecord: 11.2ms)
What is going on with the Pilgrim create controller?
You are trying to create a new pilgrim object by calling
#pilgrim = #trip.pilgrims.build(params[:pilgrim])
in the PilgrimsController. But Parameters: {"utf8"=>"✓", "authenticity_token"=>"kOE06m3DNax43BOLYZ6t1lS7/T4wOWb2xM8m/mlQzvA=", "commit"=>"Create Pilgrim", "trip_id"=>"3"} Doesn't contain any pilgrim paramters. So the problem is with the form used for creating a new pilgrim

Polymorphic Nested Form with Paperclip in Rails 3.1.3

My models:
class NewsItem < ActiveRecord::Base
has_many :file_uploads, :as => :uploadable
accepts_nested_attributes_for :file_uploads, :allow_destroy => true
end
class FileUpload < ActiveRecord::Base
belongs_to :uploadable, :polymorphic => true
has_attached_file :upload, :styles => {:thumb => '100x100>'}
end
Form Code (nested within NewsItem)
...
<%= f.fields_for :file_uploads do |upload| %>
<div class="file_upload">
<%= upload.file_field :upload %>
</div>
...
<% end %>
...
On submit I get the following error: "unknown attribute: upload". Here are the params:
{"utf8"=>"✓",
"authenticity_token"=>"MBfxJ4XTizCXv3Mpu971VHCm60bS3Y84Kdxfe+VJD2w=",
"news_item"=>{"title"=>"",
"body"=>"",
"published_date"=>"",
"file_uploads_attributes"=>{"0"=>{"upload"=>#<ActionDispatch::Http::UploadedFile:0x000001070112a8 #original_filename="rails-dd352fc2630e5f9aa5685ef1d7fe5997.png",
#content_type="image/png",
#headers="Content-Disposition: form-data; name=\"news_item[file_uploads_attributes][0][upload]\"; filename=\"rails-dd352fc2630e5f9aa5685ef1d7fe5997.png\"\r\nContent-Type: image/png\r\n",
#tempfile=#<File:/var/folders/hb/2bkct63171lck8d3sg0xfq0c0000gn/T/RackMultipart20111204-3216-71in7a>>,
"name"=>"",
"caption"=>""}}},
"commit"=>"Create News item"}
I'm using Rails 3.1.3 and paperclip "~> 2.4".
I'd avoid generic terms like "uploadable" because the resultant term "upload" has the potential for collision.
youavmatchulsky's suggestions are good too - if you have attr_accessible anywhere you'll need to make file_uploads_attributes accessible as well.
Also, the params don't look like the form is multipart, so I'd force it with :multipart => true in the call to form_for
EDIT: Even though it's supposed to happen automagically, you may have to explicitly accept_nested_attributes_for the join, and then on the join model accept_nested_attributes_for :uploadable -- I've found anaf to be pretty weird with things like polymorphic joins sometimes
Restarting the rails app fixed the problem. I'm guessing I installed the gem but did not restart, leading to the error above. Lesson learned: always restart after installing a gem.

Resources