2

在我们的Rails应用程序,有3种型号:导轨的has_many:通过关联:保存实例到连接表

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 %> 

这个“作品”,因为,当我们通过表单创建一个新的日历,它在Rails的控制台显示出来,当我们键入Calendar.all

但是,似乎没有新的@administration正在创建,并且管理表没有更新,因为当我们在控制台中输入Administration.all时什么也没有返回。

我们认为管理表是用户表和日历表之间的连接表,分别包含user_idcalendar_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

'User.find()。calendars'返回任何东西? – Ojash

+0

是的,它返回:SyntaxError:(irb):1:语法错误,意外的'<',期待')' User.find()。日历 –

回答

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 

更新:

还有就是日历用户相关联的错误。这应该是正确的:

​​
+0

非常感谢,它确实解决了问题。我们仍然有一个小问题:我们在'administration'表中定义了一个'role'列,当创建日历(和相应的管理)时,我们需要current_user默认获取'creator'。我尝试过'current_user.administration.role <<“Creator”'但它似乎没有办法。对不起,如果这是一个愚蠢的问题。 –

+1

这个答案在控制器动作中人为地将两个类绑定在一起,这通常被认为是反模式。要回答你最近的评论@ThibaudClement,如果你在我的答案中使用了第一个例子,你可以做一些事情:'@calendar.administration.role ='creator',因为'administration'对象是在初始化时创建的。 –

+0

谢谢。我们试图实现你所建议的(我们认为),但得到了一些错误。任何想法出了什么问题? –

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发生在从数据库实例化或加载对象后发生。

+0

谢谢。我不确定我是否理解这部分内容:“3.times {administrations.build}”。你能解释一下吗? –

+0

对不起,我已经更新了我的答案,以提供可能更容易理解的解释。现在,我们只需构建3个新的'Administration'对象,所有这些对象都使用关联中的'autosave:true'语句自动保存。 –

+0

非常感谢您的时间。 –

相关问题