Как вложить форму богатого много-много ассоциаций? - PullRequest
0 голосов
/ 05 января 2012

Обновление для предотвращения неправильных ответов:

  • На товаре много изображений товара
  • Есть много товаров и много сцен
  • У продукта есть одно изображение для каждой сцены, чтобы изображение продукта соответствовало этой сцене

Оригинальный вопрос:

У меня есть две таблицы (Сцены и продукты) с отношением многих ко многим через третью таблицу (ProductImages).У ProductImages есть три поля: scene_id, product_id и image.Теперь я хочу вложить форму для экземпляра ProductImage в форму Product для каждой сущности Scenes.

Поэтому, когда у меня будет три Scenes, я хочу показать три поля «изображения» внутри каждого Product.форма.Эти три поля должны всегда отображаться, даже если связь еще не существует.

Может кто-нибудь сказать, пожалуйста, как это сделать?У меня отношения определены правильно (я думаю), и я использую плагин Paperclip для прикрепления изображения.


Обновление

Чтобы уточнить, что мойВот как выглядят модели, вот идея:

Scenes:
| id | name      | background-image   |
|----|-----------|--------------------|
| 1  | kitchen x | a picture          |
| 2  | kitchen y | an other picture   |
| 3  | kitchen z | just other picture |

Products:
| id | name         | price | material |
|----|--------------|-------|----------|
| 1  | countertop x | 100   | wood     |
| 2  | countertop y | 33    | metal    |
| 3  | tap x        | 95    | chrome   |

ProductImages:
| id | product | scene | image     |
|----|---------|-------|-----------|
| 1  | 1       | 1     | some pic  |
| 2  | 1       | 2     | good pic  |
| 3  | 1       | 3     | weird pic |
| 4  | 2       | 1     | a pic     |
| 5  | 2       | 2     | one pic   |
| 6  | 2       | 3     | other pic |

И моя цель - вложить форму для поля изображения ProductImages внутри формы продуктов.

Я также добавил этот метод в products_controller.rb."ep" - продукт, который собирается редактировать;этот метод вызывается в начале метода редактирования.

def check_relation_with_scenes(ep)
    Scene.all.each do |s|
        ProductImage.find_or_create_by_product_id_and_scene_id(:product_id => ep.id, :scene_id => s.id)
    end
end

Ответы [ 4 ]

1 голос
/ 10 января 2012

Вы уверены, что хотите, чтобы таблица ссылок содержала информацию об изображении? Похоже, что изображения являются специфическими для Сцены, т.е. каждая Сцена имеет изображение.

Модели / scene.rb

class Scene < ActiveRecord::Base

  has_many :products_scenes, :dependent => :destroy
  has_many :products, :through => :products_scences     

  has_attached_file :scene_image, :path => "../uploads/:attachment/:id/:style/:filename", :url => "../uploads/:attachment/:id/:style/:filename"

end

Модели / products_scenes.rb

class ProductsScenes < ActiveRecord::Base

  belongs_to :product
  belongs_to :scene

end

Модели / product.rb

class Product < ActiveRecord::Base

  has_many :products_scenes, :dependent => :destroy
  has_many :scenes, :through => :products_scenes

  accepts_nested_attributes_for :scenes, :allow_destroy => true

end

контроллер / product_controller.rb

class ProductsController < ApplicationController

  def new
    @product = Product.new
    @product.scenes.build
  end
end

вид / продукт / _form.hmtl.haml

= form_for(@product) do |f|
  = render @product.scenes
    = link_to "Add", "#add", :id => "add-scene"

Вид / сцены / _scene.html.haml

= fields_for "product[scenes_attributes][]", scene do |scene_form|
  %li.scene_list
    .left_field
      = scene_form.label :scene_image
    .right_field
      = scene_form.file_field :scene_image
    %span.right_action_negative
      = link_to("Remove", "#delete", :class => "delete-scene")

публичный / JavaScripts / application.js

  $('a#add-scene').click(function() {
    $('#scene_list li:first').clone().find('input').val('').end().appendTo('#scene_list');
  });

  $('.delete-scene').live('click', function() {
    if ($('#scene_list li').length > 1)
         $(this).parent().parent().remove();
        else
         alert('No scenes listed.');
  });
1 голос
/ 15 января 2012

Должен признать, что эти ассоциации кажутся очень странными и лично заставят пересмотреть мой дизайн;Я предполагаю, что это причина, по которой не было много ответов на ваш вопрос.Несмотря на это, я думаю, что это больше суть того, что вы ищете:

models / scene.rb

 class Scene < ActiveRecord::Base
   has_many :product_images
   has_many :products, :through=>:product_images
   accepts_nested_attributes_for :products
 end

models / product.rb

 class Product < ActiveRecord::Base
   has_many :product_images
   has_many :scenes, :through=>:product_images
   accepts_nested_attributes_for :product_images
 end

models / product_image.rb

 class ProductImage < ActiveRecord::Base
   belongs_to :scene
   belongs_to :product
 end

Я предположил, что сцена - это ваша «родительская» форма, и продукты вложены в каждую сцену, и у каждого продукта есть форма product_image.

views / scenes / _form.html.erb

 <%= form_for @scene do |f| %>
   <%= f.error_messages %>
   <p>
     <%= f.label :name %><br />
     <%= f.text_field :name %>
   </p>
   <p>
     <%= f.label :background_image %><br />
     <%= f.text_field :background_image %>
   </p>
   <fieldset><legend>Products</legend>  
    <%= f.fields_for :products do |product_form| %>
     <%= render :partial=>"/products/form", :locals => { :f => product_form } %>
    <% end %>
   </fieldset>

   <p><%= f.submit %></p>
 <% end %>

views / products / _form.html.erb

  <p>
   <%= f.label :name %><br />
   <%= f.text_field :name %>
  </p>
  <p>
   <%= f.label :price %><br />
   <%= f.text_field :price %>
  </p>
  <p>
   <%= f.label :material %><br />
   <%= f.text_field :material %>
  </p>

  <fieldset><legend>Product Images</legend>
   <%= f.fields_for :product_images do |pi_form| %>
    <%= render :partial=>"/product_images/form", :locals => { :f => pi_form } %>
   <% end %>
  </fieldset> 

views / product_images / _form.html.erb

 <p>
  <%= f.hidden_field :scene_id %>
  <%= f.hidden_field :product_id %>
 </p>

 <p>
  <%= f.label :image %><br />
  <%= f.text_field :image %>
 </p>

controllers / scenes_controller.rb

def new
 @scene = Scene.new
 3.times do
  @scene.products.build.product_images.build
 end
end

def create
 @scene = Scene.new(params[:scene])
 if @scene.save
   redirect_to @scene, :notice => "Successfully created scene."
 else
   render :action => 'new'
 end
end

Я также заметил, что в вашей таблице определено, что таблица product_images показывает столбцы 'scene' и 'product'.Возможно, это просто опечатка, но столбцы должны быть соответственно scene_id и product_id.Удачи!

0 голосов
/ 15 января 2012

Предполагая, что у вас следующая структура модели, вот решение вашей проблемы:

class Product < ActiveRecord::Base
  has_many :products_images  
  has_many :scenes, :through => :products_images
  accepts_nested_attributes_for :products_images
end

class ProductImage < ActiveRecord::Base
  belongs_to :product
  belongs_to :scene
end

class Scene < ActiveRecord::Base
  has_many :products_images
end

в вашем контроллере

def new
  @product = Product.new
  (3-@product.products_images.size).times {@product.products_images.build} if @product.products_images.size < 3
  #ensure always have at least 3 product_images initialized
end

в вашей форме.

<%= form_for @product do |f| %>
  <%= f.fields_for :product_images do |pf| %>
    <%= pf.file_field :image %>
  <% end %>
<% end %>

Дайте мне знать, если у вас есть какие-либо вопросы.

0 голосов
/ 10 января 2012

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

http://railscasts.com/episodes/196-nested-model-form-part-1

http://railscasts.com/episodes/197-nested-model-form-part-2

http://railscasts.com/episodes/75-complex-forms-part-3

Они, безусловно, должны помочь вам решить вашу проблему и приблизить вас к расколу пива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...