2011-05-01 62 views
0

我有兩個資源:主題和帖子。 我想弄清楚如何通過Post控件創建主題。 這些模型是這樣的:如何通過rails 3中的子控制器創建父模型? (belongs_to association)

class Topic < ActiveRecord::Base 
    has_many :posts, :dependent => :destroy 
    validates :name, :presence => true, 
        :length => { :maximum => 32 } 
    attr_accessible :name 
end 

class Post < ActiveRecord::Base 
    belongs_to :topic, :touch => true 
    has_many :comments, :dependent => :destroy 
    accepts_nested_attributes_for :topic 
    attr_accessible :name, :title, :content, :topic 
end 

帖子/ _form.html.erb:

<%= simple_form_for @post do |f| %> 
    <h1>Create a Post</h1> 
    <%= f.input :name, :label => false, :placeholder => "Name" %> 
    <%= f.input :title, :label => false, :placeholder => "Title" %> 
    <%= f.input :content, :label => false, :placeholder => "Content" %> 
    <%= f.input :topic, :label => false, :placeholder => "Topic" %> 
    <%= f.button :submit, "Post" %> 
<% end %> 

posts_controller.rb#創建:

def create 
    @post = Post.new(params[:topic]) 
    respond_to do |format| 
    if @post.save 
     format.html { redirect_to(@post, :notice => 'Post was successfully created.') } 
    else 
     format.html { render :action => "new" } 
    end 
    end 
end 

隨着職位/ _form.html.erb我可以創建帖子,但不會隨之創建相關主題。任何人都可以告訴我爲什麼我會得到這種行爲,並可能如何糾正?我使用Ruby 1.9.2,Rails 3.0.7和simple_form gem。

回答

1

根據你想要做什麼,我可以看到兩個選項。

選項1:使用文本框來創建或查找現有的主題(與您一樣)。在你的控制器,你會寫如下:

def create 
    topic_name = params[:post].delete(:topic) 
    @topic = Topic.find_or_create_by_name(topic_name) 
    @post = Post.new(params[:post]) 
    @post.topic = @topic 
    if @post.save 
    format.html { redirect_to(@post, :notice => 'Post was successfully created.') } 
    else 
    format.html { render :action => "new" } 
    end 
end 

這是快速和骯髒的方式。它會爲您輸入的每個topic嘗試按名稱查找該主題,或者創建並分配該主題。但是,這很容易出錯。如果您的主題集有限,則有一種更簡單的方法。

選項2:使用選擇框,可用主題列表。在你的觀點寫:

<%= simple_form_for @post do |f| %> 
    <h1>Create a Post</h1> 
    <%= f.input :name, :label => false, :placeholder => "Name" %> 
    <%= f.input :title, :label => false, :placeholder => "Title" %> 
    <%= f.input :content, :label => false, :placeholder => "Content" %> 
    <%= f.association :topic %> 
    <%= f.button :submit, "Post" %> 
<% end %> 

這將呈現一個選擇框與可能的主題。而在你的控制器,你只需要編寫:

def create 
    @post = Post.new(params[:post]) 
    if @post.save 
    format.html { redirect_to(@post, :notice => 'Post was successfully created.') } 
    else 
    format.html { render :action => "new" } 
    end 
end 

雖然這第二個選擇是很容易的,這是不容易在飛行中添加主題。您可以在兩者之間做一些事情,使用自動填充字段,該字段可以允許在存在的情況下查找值,或者如果它們不存在則添加新值。

希望這會有所幫助。

+0

這個工作!我正在計劃實現該領域的自動完成,並知道選擇框的方法。非常適合你的時間。 – BasicObject 2011-05-01 23:07:32

1

您是否正在服務器日誌中發生質量分配錯誤?您可能需要將topic_attributes添加到您的attr_accessible列表中。

+0

我得到一個大規模分配錯誤,並且我不再感謝您的建議。主題仍然沒有被創建:( – BasicObject 2011-05-01 04:23:11

+0

我對simple_form一無所知,但對於常規的嵌套表單,您可以在視圖中使用'f.fields_for:topic do | topic |'。關於nested_form的railscast:http://asciicasts.com/episodes/196-nested-model-form-part-1 – chrismealy 2011-05-01 05:47:47

3

Railscasts有幾個關於這個問題的劇集。 插曲(訂閱所需的)16

的源代碼: https://github.com/railscasts/016-virtual-attributes-revised

而且這一集 http://railscasts.com/episodes/57-create-model-through-text-field

的意見/產品/與_form.rhtml

<p> 
<label for="product_category_id">Category:</label><br /> 
<%= f.collection_select :category_id, Category.find(:all), :id, :name, :prompt => "Select a Category" %> 
or create one: 
<%= f.text_field :new_category_name %> 
</p> 

型號/ product.rb

belongs_to :category 
attr_accessor :new_category_name 
before_save :create_category_from_name 

def create_category_from_name 
create_category(:name => new_category_name) unless new_category_name.blank? 
end 

我認爲Ryan的分類解決方案比@nathanvda的選項1更優雅。它處理的是Model中的數據而不是Controller。如果你需要在不同的控制器/操作中做同樣的工作,你會看到好處。

相關問題