在我们的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.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
我们已按如下方式创建calendar#create
操作:
def create
@calendar = current_user.calendars.build(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 "Post", class: "btn btn-primary" %>
<% end %>
这个“有效”,因为当我们通过表单创建新日历时,当我们输入Calendar.all
时,它确实会显示在Rails控制台中。
但是,似乎没有创建新的@administration
并且管理表未更新,因为当我们在控制台中键入Administration.all
时没有任何内容返回。
我们认为管理表是User表和Calendar表之间的连接表,分别包含user_id
和calendar_id
列,在创建新日历时会自动更新。
我们怎样才能做到这一点?我们是否需要创建特定的administration#create
操作?
更新:根据评论和答案,我们实施了以下CalendarsController
:
class CalendarsController < ApplicationController
def create
@calendar = current_user.calendars.build(calendar_params)
if @calendar.save
current_user.administrations << @calendar
@calendar.administration.role = 'creator'
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
...
但是,这会返回以下错误:
ActiveRecord::AssociationTypeMismatch in CalendarsController#create
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:6:in `create'
我们错过了什么吗?
答案 0 :(得分:3)
如果你使用current_user.calendars.build(calendar_params),你将只获得新的日历,而不是管理。
如果您使用current_user.calendars.create(calendar_params),您将获得管理和日历保存到数据库中。
如果您想先检查日历是否成功保存,我会使用这种方法:
def create
@calendar = Calendar.build(calendar_params)
if @calendar.save
current_user.administrations << @calendar
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
更新:
将日历与用户关联时出错。这应该是正确的:
def create
@calendar = current_user.calendars.build(calendar_params)
if @calendar.save
current_user.calendars << @calendar
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
答案 1 :(得分:2)
是的,你绝对这样做!您没有收到新的Administration
对象,因为您并没有要求系统提供一个。
如果你确实真的需要在每次创建Administration
时创建一个新的Calendar
对象,你可以这样做:
class Calendar < ActiveRecord::Base
attr_reader :administration
def initialize(params)
@administration = Administration.new(params[:id])
end
end
class Administration < ActiveRecord::Base
def initialize(id_param_from_calendar)
calendar_id = id_param_from_calendar
end
end
显然,这不是最佳做法,因为它会在代码中注入依赖项。现在,无论如何,您的Calendar
类都知道Administration
类不仅存在,而且还使用其id
列进行初始化。这只是回答你问题的一个例子。
另一个示例是在after_initialize
类中包含Calendar
挂钩(请注意autosave: true
,这对确保自动保存子对象很有用):
class Calendar < ActiveRecord::Base
has_many :administrations, autosave: true, dependent: :destroy
after_initialize :init_admins
def init_admins
# you only wish to add admins on the newly instantiated Calendar instances
if new_record?
3.times { Administration.new self }
end
end
end
除此之外,您还可以在after_create
挂钩中包含上述逻辑。唯一的区别是在创建对象后发生after_create
,在实例化或从数据库加载对象后发生after_initialize
。