我在ruby on rails上的关联有问题。 我有这个协会:
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
当我创建计划时,我想关联一个或多个播放。预先创建播放。 播放有很多属性,其中:title 和:id 当然。
program_controller:
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 gem):
<%= 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 %>
现在,当我想在索引中显示程序时,我还想显示相关播放的标题。但是当我写道:
program.plays.title
错误告诉我标题不是程序的方法......为什么?我不明白。这种关联是真实的,因为当我放入rails控制台时:
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
时,在rails控制台中:
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
答案 0 :(得分:0)
协会看起来很好。你遇到的问题是你正在调用program.plays.title
,但请记住,program.plays会有一系列的游戏,而不仅仅是一个游戏,所以你不能直接在那里打电话。
这取决于你想要做什么,例如,如果你想要第一个游戏的标题,你可以做program.plays.first.title
或者如果您想要打印所有播放标题,您可以执行类似
的操作program.plays.each do |play|
play.title
end
我假设程序中充满了代码中的现有程序
你遇到的另一个问题是你不允许控制器上的program_id所以当你创建播放时,由于不允许,因此不保存具有关联的属性program_id,所以只需在你的参数上添加program_id像这样的方法
def program_params
params.require(:program).permit(:start_date, plays_attributes: [:title, :program_id])
end