2013-04-01 62 views
1

我是Rails的新手,所以我可以忽略一些簡單的東西。我有一個叫做故事的Rails模型。每個故事都有一些細節,每個細分都屬於一個故事。我使用相同的表單通過使用表單的fields_for部分並將故事模型設置爲accep_nested_attributes_for:segments來創建故事及其第一個片段。我目前能夠使用該表格同時創建故事和細分。如果一個Rails模型has_many孩子,我該如何存儲第一個ID?

的問題是,每個故事也需要存儲其第一段的ID,但是當我保存的故事,段尚未保存,因此它目前還沒有一個id存儲在故事裏,我一直沒能找到一個手柄,該段的形式提交後,這樣我可以先保存段創建之前的故事。所以我的問題是如何在故事中保存first_segment_id的記錄?

下面的代碼可能是相關的:

在app /模型/ story.rb

class Story < ActiveRecord::Base 
    attr_accessible :segments_attributes 
    has_many :segments 
    accepts_nested_attributes_for :segments 
end 

在app /模型/ segment.rb

class Segment < ActiveRecord::Base 
    attr_accessible :words 
    belongs_to :story 
end 

in app/views/stories/ _ form.html.erb

<%= form_for(@story) do |f| %> 

    #...stories fields... 

    <%= f.fields_for :segments do |segment_form| %> 
    <div class="field"> 
     <%= segment_form.label :words %><br /> 
     <%= segment_form.text_area :words %> 
    </div> 
    <% end %> 

    <div class="actions"> 
    <%= f.submit %> 
    </div> 
<% end %> 

在app /控制器/故事 _ controller.rb

def new 
    @story = Story.new 

    @segment = @story.segments.build 

    # If I try replacing the above with @segment = @story.segments.create 
    # then I get the error message "You cannot call create unless the 
    # parent is saved," which is problematic because I need to find some way 
    # to get the id of @segment to save in the parent story, but the segment 
    # won't have an id until after it has been saved. 

    respond_to do |format| 
     format.html # new.html.erb 
     format.json { render json: @story } 
    end 
    end 

    def create 
    @story = Story.new(params[:story]) 

    # @segment.save 
    # @story.first_segment_id = @segment.id 
    # If I uncomment the above two lines, I get the error message 
    # "undefined method `save' for nil:NilClass". It appears that 
    # @segment hasn't been passed from the "new" method above to 
    # this method as a handle of the first segment created, so I'm not 
    # able to save it to get an id for it before saving the story. 
    # Is there some way to save the segment here? 

    respond_to do |format| 
     #...if @story.save... 
    end 
    end 

提交表單params哈希表如下所示:

{ "story"=>{ Various_other_story_fields, 
"segments_attributes"=>{"0"=>{"words"=>"dfsdsa"}}}, 
"commit"=>"Create Story"} 

有沒有如何在故事中保存第一部分的ID?我想也許我需要添加一個before_create我的故事模型內部,而不是,但我不知道怎麼辦了這一點。

回答

1

我想不同的方法處理這個,添加數字sort_orderSegment讓你不依靠Segment ID,以確定他們去的順序。然後,你可以定義像您Story模式下,而不是明確參考第一部分在數據庫:

def first_segment 
    segments.order(:sort_order).first 
end 

如果你一定需要在第一段ID存儲在故事中,你可以.save的故事,以便它知道它的ID,保存它的孩子,知道他們的ID。喜歡的東西:

def create 
    @story = Story.new(params[:story]) 
    @story.save # Save the story and its child segment so that they both have IDs 
    @story.first_segment_id = @story.segments.first.id 
    @story.save 
    ... 
end 
+0

我不認爲你的建議將工作的第二種方式。它試圖在保存段之前獲取段的ID,此時該段沒有ID。 – 3nafish

+0

+1你建議的第一種方法可以工作,它已經指導我使用segments.first的更簡單的方法(因爲創建的第一個應始終是具有第一個id的那個,在我的情況下,順序不會改變)......我不敢相信我幾天來一直忽視這一點,但後來我對Rails非常陌生。然而,每次調用.first方法引起我關注的是它效率低下。這是會經常做的事情,所以如果可能的話,我仍然想找到一種方法來存儲個人ID。 – 3nafish

+0

對不起,我應該更清楚地知道,在你已經保存了故事(沒有外鍵)和該段一次之後,該代碼就會運行。但是,只要不需要更改排序,只要將ID用作排序就可以工作。我不認爲這樣做效率不高:我懷疑大多數數據庫服務器足夠聰明,可以跳到與外鍵匹配的聚集索引中的第一條記錄。 –

1

你應該能夠做這樣的事情:

class Story < ActiveRecord::Base 
    attr_accessible :segments_attributes 
    has_many :segments 
    has_one :first_segment 
    accepts_nested_attributes_for :segments 
end 

def new 
    @story = Story.new 

    @segment = @story.segments.build 
    @story.first_segment = @segment 
    ... 

你必須story_id添加到您的段表。

+0

所以,如果我正確理解你,first_segment會是自己的模型?我並不完全瞭解它與其他模型的關係。你能更清楚一點嗎? – 3nafish

+0

這是一個has_one關係,因此外鍵位於擁有的模型中(請參閱http://guides.rubyonrails.org/association_basics.html#the-has_one-association)。由於rails實現關聯的方式,這只是在db中的記錄之間創建一個新的關係。唯一需要注意的是,一旦故事被保存,Story#first_segment和Story#segments.first將具有相同的數據,但不會是同一個對象。 –

+0

哈哈,您鏈接的頁面太熟悉了。 (我在今天的大多數時間都在盯着它)。+1提出了一種可行的方法,但如果可能的話,我希望找到一種不需要創建額外模型的方法。我可能需要更新該段,因此將它們存儲在兩個地方並不理想。另外,每個細分都有相關的文本,所以只將它存儲在一個地方對記憶來說是最好的。 – 3nafish

相關問題