Rails: нужна помощь в понимании таблицы соединений, вложенных форм, ассоциаций - PullRequest
0 голосов
/ 27 сентября 2018

Я учусь на Rails, и мой проект - сделать приложение для рецептов.В моем приложении для рецептов есть модели Recipe, Ingredient и другие, но важно то, что Ingredient должен быть единственным ингредиентом такого рода в таблице.Строка будет просто идентификатор и имя.В таблице может быть только один «рис», поэтому любой Recipe, который использует рис в качестве ингредиента, использует тот же ряд.Таким образом (я думаю) я могу фильтровать Recipe с по Ingredient с.

Я должен использовать вложенную форму при создании / редактировании Recipe, чтобы пользователь мог заполнить информацию рецепта и ингредиенты на одном экране, включая добавление нового Ingredients и выбор ингредиентов извыпадающий список для выбора.При редактировании пользователь также может удалять (разъединять) и Ingredient из Recipe.

Я понимаю, что мне понадобится объединяющая таблица (recipes_ingredients ??, если так, как называется модель, RecipesIngredient?

Я не совсем понимаю, как будет работать эта вложенная форма. Я должен создать fields_for для всех Ingredient с? Как отсоединиться и создать?

Может бытькто-то может указать мне правильное направление, где я могу прочитать об этом. Я долго ломал голову, даже запускаю проект дважды. Я расстраиваюсь, но чувствую, что я так близок к пониманиюэто.

Я также пытался использовать simple_form и cocoon, но я чувствую, что это просто смутило меня еще больше.

Любой свет, проливающийся на эту тему, был бы удивительным. Спасибо.

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Простыми словами вы описываете ассоциации многие-ко-многим.

Итак, прежде всего, взгляните на руководство https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Вам нужно 3 модели.Модель Recipe, модель Ingredient и модель Recipe_Ingredient.

Ι Полагаю, у вас уже есть две модели, Рецепт и Ингредиент, поэтому давайте посмотрим модель таблицы объединения.

Сначала сгенерируйте миграцию:

rails generate migration create_recipe_ingredients   

В db/migrate/***create_recipe_ingredients.rb создайте таблицу соединений

def change
 create_table :recipe_ingredients do |t|
   t.integer :ingredient_id, :recipe_id
 end
end

Итак, ваши модели:

class Recipe < ApplicationRecord
  has_many:recipe_ingredients
  has_many:ingredients, through: :recipe_ingredients 
end

class RecipeIngredient < ApplicationRecord
  belongs_to :recipe
  belongs_to :ingredient
end

class Ingredient < ApplicationRecord
  has_many:recipe_ingredients
  has_many:recipes, through: :recipe_ingredients
end

Запустите и протестируйте ассоциации на вашей консоли:

irb:> recipe=Recipe.first
irb:> ingre=Ingredient.first
irb:> ingre.recipes << recipe
irb:> ingre.recipes #Recipes with this ingredient
irb:> recipe.ingredients #The ingredients of this specific recipe.
irb:> Ingredient.all #List all your ingredients.
irb:> Recipe.all #List all your recipes.
0 голосов
/ 27 сентября 2018

Это довольно типичная настройка таблицы соединения:

enter image description here

Здесь у нас есть нормализованная таблица с именем ingredients, которая служит основной записью дляингредиент и recipe_ingredients, который соединяется с таблицей recipe.

В Rails мы настроим это как has_many through: ассоциацию:

class Recipe < ApplicationRecord
  has_many :recipe_ingredients
  has_many :ingredients, through: :recipe_ingredients
end

class Ingredient < ApplicationRecord
  has_many :recipe_ingredients
  has_many :recipes, through: :recipe_ingredients
end

class RecipeIngredient < ApplicationRecord
  belongs_to :recipe
  belongs_to :ingredient
end

Причина, по которой вы хотите использоватьhas_many through:, а не has_and_belongs_to_many - это то, что последний «безголовый», так как нет модели.Это может показаться хорошей идеей, пока вы не поймете, что нет способа получить доступ к дополнительным столбцам (например, к количеству).

При именовании таблиц соединения для has_many through: вы должны следовать схеме [thing in singular]_[thing in plural]благодаря тому, что Rails разрешает имена классов из имен таблиц.Например, использование recipes_ingredients приведет к отсутствующей постоянной ошибке, так как Rails попытается загрузить Recipes::Ingredient.Сама модель соединения должна называться SingularSingular.

Конечно, вы также можете называть таблицы соединений любым именем, подходящим для домена.

Чтобы добавить вложенные строки, вы бы использовали вложенные атрибуты и fields_for :recipe_ingredients:

<%= form_for(@recipe) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <fieldset>
    <legend>Ingredients</legend>
    <%= fields_for :recipe_ingredients do |ri| %>
    <div class="nested_fields">
       <div class="field">
         <%= ri.label :ingredient %>
         <%= ri.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
       </div>
       <div class="field">
         <%= ri.number_field :quantity %>
       </div>
    </div>
    <% end %>
  </fieldset>
<% end %>

Однако вложенные поля во многих отношениях являются препятствием, позволяющим создавать / изменять несколько моделей одновременно.UX и поток приложений, объединяющий все вместе, вряд ли идеален.

Чтобы обеспечить хороший UX, возможно, лучше применить инкрементные сохранения (пользователь сохраняет рецепт перед добавлением ингредиентов в фоновом режиме с помощью AJAX) и добавитьингредиенты через серию запросов ajax POST к /recipies/:recipe_id/ingredients.Но это тема всего учебного пособия сама по себе, и, скорее всего, к ней следует вернуться после того, как вы поймете основы.

См .:

...