Вопрос

I am trying to build a CRUD controller and form in Rails 3.

I have

class Publication < ActiveRecord::Base

  has_many :posts

end

where Posts is a STI model :

class Post < ActiveRecord::Based
  attr_accessible :title, :description
end

and I have a few inherited models:

class Image < Post
end

class Video < Post
end

class Status < Post
end

etc.

I want to create a CRUD for Publication, where the user is able to add as many Posts as they want, dynamically adding nested form for any type of Post.

Is there a gem I could use that supports such nested forms with STI ?

I tried to build a form, but I need to amend the Publication class and introduce nested attributes for each additional inherited model. Is there a way to avoid doing this?

class Publication < ActiveRecord::Base

  has_many :videos, :dependent => :destroy
  accepts_nested_attributes_for :videos, allow_destroy: true
  attr_accessible :videos_attributes

  has_many :posts

end
Это было полезно?

Решение 2

I wrote a short blog post about this problem at: http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

I basically decided to use the cocoon gem, which provides two helper methods - link_to_add_association and link_to_remove_association, which dynamically add the respective decorated class fields to the form (such as Post, Image or Video

# _form.html.haml

= simple_form_for @publication, :html => { :multipart => true } do |f|

  = f.simple_fields_for :items do |item|
    = render 'item_fields', :f => item
  = link_to_add_association 'Add a Post', f, :items, :wrap_object => Proc.new { |item| item = Item.new }
  = link_to_add_association 'Add an Image', f, :items, :wrap_object => Proc.new { |item| item = Image.new }
  = link_to_add_association 'Add a Video', f, :items, :wrap_object => Proc.new { |item| item = Video.new }

  = f.button :submit, :disable_with => 'Please wait ...', :class => "btn btn-primary", :value => 'Save'

The :wrap_object proc generates the correct object, to be rendered inside _item_fields partial, like:

# _item_fields.html.haml

- if f.object.type == 'Video'
  = render 'video_fields', :f => f
- elsif f.object.type == 'Image'
  = render 'image_fields', :f => f
- elsif f.object.type == 'Post'
  = render 'post_fields', :f => f

Другие советы

You can simply do like this.

In your Publication Controller

class PublicationsController < ApplicationController
    def new
       @publication = Publication.new
       @publication.build_post
    end
end

Your Models should be like this

class Publication < ActiveRecord::Base
    has_many :posts, dependent: :destroy
    accepts_nested_attributes_for :posts    
end

class Post < ActiveRecord::Base
    belongs_to :publication
    Post_options = ["Image", "Video", "Status"]
end

In your form

<%= form_for(@publication) do |f| %>
  <p>
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </p>

  <p>
    <%= f.label :description %><br>
    <%= f.text_area :description %>
  </p>

   <%= f.fields_for :post do |p| %>
      <%= p.label :post_type %>
      <%= p.select(:post_type, Post::Post_options , {:prompt => "Select"}, {class: "post"}) %>
   <% end %>
  <p>
    <%= f.submit %>
  </p>
<% end %>

Note: You should have a post_type attribute in your Post model to get this worked.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top