Как создать родительскую модель через дочерний контроллер в рельсах 3?(принадлежит ассоциации) - PullRequest
1 голос
/ 01 мая 2011

У меня есть два ресурса: темы и сообщения. Я пытаюсь выяснить, как я могу создать тему через контроллер сообщений. Модели выглядят так:

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

С posts / _form.html.erb я могу создавать сообщения, но связанная с ними тема не создается. Может кто-нибудь сказать мне, почему я получаю такое поведение и, возможно, как это исправить? Я использую Ruby 1.9.2, Rails 3.0.7 и гем simple_form.

Ответы [ 3 ]

3 голосов
/ 05 ноября 2012

Railscasts имеет несколько эпизодов об этой проблеме.эпизод 16 (необходима подписка)

Исходный код: https://github.com/railscasts/016-virtual-attributes-revised

И этот эпизод http://railscasts.com/episodes/57-create-model-through-text-field

views / products / _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>

models / 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

Я думаю, что решение Райана по категориям более элегантно, чем вариант 1.nathanvda, поскольку он обрабатывает данные в Model вместо Controller.Если вам нужно выполнить одну и ту же работу в разных контроллерах / действиях, вы увидите преимущества.

2 голосов
/ 01 мая 2011

В зависимости от того, что вы хотите сделать, я вижу два варианта.

Вариант 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

Хотя этот второй вариант действительно прост, добавлять темы на лету не так просто. Вы можете сделать что-то промежуточное, используя поле автозаполнения, которое позволит либо искать значения, если они существуют, либо добавлять новые значения, если они не существуют.

Надеюсь, это поможет.

1 голос
/ 01 мая 2011

Получаете ли вы массовые ошибки назначения в журнале сервера?Возможно, вам потребуется добавить: topic_attributes в ваш список attr_accessible.

...