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

非常感謝您的時間。 –

相關問題