Ассоциация Rails не работает с атрибутами - PullRequest
0 голосов
/ 24 мая 2018

У меня проблема с моей ассоциацией в ruby ​​на рельсах.У меня есть ассоциация:

class Play < ApplicationRecord
  has_many :program_plays
  has_many :programs, through: :program_plays
end

class ProgramPlay < ApplicationRecord
  belongs_to :program
  belongs_to :play
end

class Program < ApplicationRecord
  has_many :program_plays
  has_many :plays, through: :program_plays
  accepts_nested_attributes_for :plays
end

Когда я создаю Программу , я хочу связать одну или несколько Play . Play создаются заранее. Play имеет много атрибутов, чьи : title и : id конечно.

Контроллер программы:

class Admin::ProgramsController < Admin::AdminController

  def index
    @programs = Program.all
  end

  def new
    @program = Program.new
    @program.plays.build
  end

  def create
    @program = Program.new(program_params)

    if @program.save
      redirect_to admin_programs_path, notice: ''
    else
    end
  end

  private

  def set_program
    @program = Program.find(params[:id])
  end

  def program_params
    params.require(:program).permit(:start_date, plays_attributes: [:title])
  end
end

Форма Программа (с гемом simple_form):

<%= simple_form_for [:admin, @program] do |f| %>
  <%= f.error_notification %>

      <%= f.association :plays %>

      <%= f.input :start_date, as: :datetime, minute_step: 15, label: 'Heure' %>

    <%= f.button :submit, 'Poster', class: 'button red-full' %>

<% end %>

Теперь, когда я хочу отобразить Программу в моем индексе, я также хочу отобразить название связанного Play .Но когда я пишу:

program.plays.title

ошибка говорит мне, что название не является методом программы ... Почему?Я не понимаюАссоциация реальна, потому что, когда я вставляю в консоль рельсы:

program.plays.to_a

, у меня есть:

 Play Load (5.4ms)  SELECT "plays".* FROM "plays" INNER JOIN "program_plays" ON "plays"."id" = "program_plays"."play_id" WHERE "program_plays"."program_id" = $1  [["program_id", 21]]
=> []

Вы видите проблему?Я ищу это давным-давно ... Я в отчаянии ...

ОБНОВЛЕНИЕ:

В консоли рельсов, когда я делаю program.plays.first.title:

  Play Load (0.5ms)  SELECT  "plays".* FROM "plays" INNER JOIN "program_plays" ON "plays"."id" = "program_plays"."play_id" WHERE "program_plays"."program_id" = $1 ORDER BY "plays"."id" ASC LIMIT $2  [["program_id", 22], ["LIMIT", 1]]
NoMethodError: undefined method `title' for nil:NilClass

Когда я делаю:

program.plays.each do |play|
  play.title
end

Результат:

  Play Load (0.5ms)  SELECT "plays".* FROM "plays" INNER JOIN "program_plays" ON "plays"."id" = "program_plays"."play_id" WHERE "program_plays"."program_id" = $1  [["program_id", 22]]
=> []

Здесь мы видим, что title пусто ...

ОБНОВЛЕНИЕ 2:

  create_table "plays", force: :cascade do |t|
    t.string "title"
    t.text "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "program_plays", force: :cascade do |t|
    t.bigint "program_id"
    t.bigint "play_id"
    t.index ["play_id"], name: "index_program_plays_on_play_id"
    t.index ["program_id"], name: "index_program_plays_on_program_id"
  end

  create_table "programs", force: :cascade do |t|
    t.datetime "start_date"
  end

Возможно, проблема здесь ...

ОБНОВЛЕНИЕ 3:

> program = Program.new
=> #<Program:0x00000000068ce8e8 id: nil, start_date: nil>
[15] pry(main)> program.id = 1
    => 1
    > program.plays.build(Play.find_by(id: 10))
  Play Load (6.2ms)  SELECT  "plays".* FROM "plays" WHERE "plays"."id" = $1 LIMIT $2  [["id", 10], ["LIMIT", 1]]
ArgumentError: When assigning attributes, you must pass a hash as an argument.
from /home/coeurcoeur/.rvm/gems/ruby-2.5.0/gems/activemodel-5.1.4/lib/active_model/attribute_assignment.rb:28:in `assign_attributes'
> program.save
   (0.1ms)  BEGIN
   (0.3ms)  ROLLBACK
=> false

1 Ответ

0 голосов
/ 24 мая 2018

Ассоциация выглядит хорошо.проблема в том, что вы звоните program.plays.title, но имейте в виду, что program.plays будет иметь коллекцию пьес, а не только одну, поэтому вы не сможете напрямую назвать заголовок.

это зависитна том, что вы пытаетесь сделать, например, если вам нужен заголовок первой пьесы, вы можете сделать что-то вроде program.plays.first.title

или если вы хотите напечатать все заголовки пьес, вы можете сделать что-то вроде

program.plays.each do |play|
  play.title
end

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

Другая проблема, с которой вы столкнулись, заключается в том, что вы не разрешаете ID программы на контроллере, поэтому при создании игрАтрибут program_id, который имеет ассоциацию, не сохраняется, потому что не разрешен, поэтому просто добавьте program_id в свой метод params, как этот

def program_params
  params.require(:program).permit(:start_date, plays_attributes: [:title, :program_id]) 
end
...