Reputation: 31
I'm a bit of a Rails noob and I'm having some trouble getting my head around an issue.
I'm using Rails 3.2.13 with the following gems (in addition to the default gems):
gem 'devise'
gem 'cancan'
gem 'cocoon'
gem 'best_in_place'
I am using cocoon to work with nested models, in this case I have a (devise) user who has_many
projects and each project has_many
tasks.
I am able to get all of the information to display (and become editable on click) with:
<% @project.tasks.each do |task| %>
<%= best_in_place task, :description, :path => tasks_path, :type => :input %>
<% end %>
My problem is that I cannot get best_in_place to save updates to my nested Task attributes.
Project Model:
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
attr_accessible :description, :name, :tasks_attributes, :user_id, :tasks
accepts_nested_attributes_for :tasks, :reject_if => :all_blank, :allow_destroy => true
end
Task Model:
class Task < ActiveRecord::Base
belongs_to :project
attr_accessible :description, :done, :hours
end
Project Controller:
class ProjectsController < ApplicationController
before_filter :authenticate_user!
def show
@project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => @project }
end
end
def update
@project = Project.find(params[:id])
respond_to do |format|
if @project.update_attributes(params[:project])
format.html { redirect_to @project, :notice => 'Project was successfully updated.' }
#format.json { head :no_content }
format.json { respond_with_bip(@project) }
else
format.html { render :action => "edit" }
#format.json { render :json => @project.errors, :status => :unprocessable_entity }
format.json { respond_with_bip(@project) }
end
end
end
end
Projects -> show.html.erb:
<% @project.tasks.each do |task| %>
<li class="module-list-item ui-state-default clear">
<section class="task-name left">
<%= best_in_place task, :description, :path => tasks_path, :type => :input %>
</section>
</li>
<% end %>
Upvotes: 3
Views: 1009
Reputation: 3000
Though this use is not officially supported (as @Ich points out), there is a workaround. No need for any additional controllers. You just need to pass a param
param to best_in_place.
class Unicycle < AR::Base
has_one :wheel
accepts_nested_attributes_for :wheel, update_only: true
end
best_in_place unicycle.wheel, :last_rotation,
path: unicycle_path(unicycle.id), type: :input,
param: "unicycle[wheel_attributes]"
Note that it's slightly more complicated for a Car
, which has_many :wheels
(or for a Unicycle
that has_one :wheel
where update_only
won't work for you).
car.wheels.each do |wheel|
best_in_place wheel, :last_rotation,
path: car_path(car.id), type: :input,
param: "car[wheel_attributes][id]=#{wheel.id}&car[wheel_attributes]"
# Note that you have to pass the ID of the wheel in this case
end
Works with v3.0.3, possibly with much earlier versions too but I haven't tested.
Upvotes: 2
Reputation: 1378
According to https://github.com/bernat/best_in_place/issues/51 this is not supported by best_in_place.
The gem's author argues that in place editing should only modify on attribute of one model, so changing another model's attributes was not in scope.
My opinion: Personally I regret that decision.
Upvotes: 0