这个问题在Rails has_many :through association: save instance into join table后跟进,我在这里重申一些事情,以便更清晰。
在我们的Rails应用程序中,有3个模型:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
以下是相应的迁移:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.integer :total_calendar_count
t.integer :owned_calendar_count
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
以下是我们要完成的任务:
当登录用户(current_user
)创建日历时,我们应该:
@calendar
并将其保存到日历表total_calendar_count
和owner_calendar_count
列为了做到这一点,我们认为我们需要处理日历#create。
在CalendarsController中,我们已经有了以下代码:
def create
@calendar = current_user.calendars.create(calendar_params)
if @calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
我们通过以下_calendar_form.html.erb
表格收集用户的数据:
<%= form_for(@calendar) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :name, placeholder: "Your new calendar name" %>
</div>
<%= f.submit "Create", class: "btn btn-primary" %>
<% end %>
我们正在考虑按如下方式更新控制器:
def create
@calendar = current_user.calendars.create(calendar_params)
@current_user.total_calendar_count += 1
@current_user.owned_calendar_count += 1
current_user.administrations << @calendar.id
@calendar.administration.role = 'Creator'
if @calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
ActiveRecord::AssociationTypeMismatch in CalendarsController#create
Administration(#70307724710480) expected, got Fixnum(#70307679752800)
unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
raise ActiveRecord::AssociationTypeMismatch, message
end
end
app/controllers/calendars_controller.rb:7:in `create'
我们怎样才能让它发挥作用?
答案 0 :(得分:1)
此行实际上导致错误:current_user.administrations << @calendar.id
。
current.administrations
传递给它时, Administration
需要Fixnum
类型的对象。
您可以通过以下方式完成相同的功能:
current_user.administrations.create(calendar_id: @calendar.id)
修改强>
OP在评论中提到这是一个好习惯。看,有规则说控制器应该是瘦的,模型应该是胖的。嗯,这意味着你应该尝试编写最少的代码,所有逻辑和提取对象应该在那里楷模。但在您的代码方案中并非如此。您应该将代码移动到模型中,然后将其调用到控制器中。
以下是:
class User < ActiveRecord::Base
def add_calendar_and_role(calendar_id, role)
self.administrations.find_by(calendar_id: calendar_id).update(role: role)
end
end
这样,您的代码简化为:
current_user.add_calendar_and_role(@calendar.id, 'Creator')
同样,您可以进一步重构控制器代码。