在Rails 5中,如何使用单个控制器操作在单独的模型中创建记录?

时间:2018-01-28 20:07:09

标签: ruby-on-rails forms models

我正在通过Rails教程创建一个詹姆斯邦德电影数据库。我有两个模型,movie.rb和theme_song.rb。这两者有以下关联:

class Movie < ApplicationRecord
  has_one :theme_song
end
class ThemeSong < ApplicationRecord
  belongs_to :movie
end

我还在routes.rb文件中表示了这个关联:

resources :movies do
  resources :theme_songs
end

我需要让用户将附加影片的细节添加到数据库中,包括一般电影信息和有关主题歌的信息。一般信息属于Movie模型,主题歌信息属于ThemeSong模型,如下面的迁移所示:

create_table :movies do |t|
  t.string :title
  t.datetime :release_date
  t.text :plot
  t.timestamps
end
create_table :theme_songs do |t|
  t.string :song
  t.string :artist
  t.references :movie, foreign_key: true
  t.timestamps
end

我有一个movies_controller.rb控制器和一个链接到控制器的new.html.erb视图。 new.html.erb视图将以下格式编码到其中:

<%= form_with model: @movie, local: true do |form| %>
  <p><strong>Movie Details</strong></p>
  <p>
    <%= form.label 'Title:' %>
    <%= form.text_field :title %>
  </p>
  <p>
    <%= form.label 'Release date:' %>
    <%= form.text_field :release_date %>
  </p>
  <p>
    <%= form.label 'Plot:' %>
    <%= form.text_area :plot %>
  </p>
  <p><strong>Soundtrack</strong></p>
  <p>
    <%= form.label 'Theme song:' %>
    <%= form.text_area :song %>
  </p>
  <p>
    <%= form.label 'Artist:' %>
    <%= form.text_area :artist %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

我需要用户能够填写该表单,提交表单,以及我的控制器创建操作以在Movie中添加新记录和一般信息,在ThemeSong中添加带有音轨信息的新记录,两个记录都已链接在协会。

这是我到目前为止在我的movies_controller.rb的相关方法中得到的代码:

def create
  @movie = Movie.new(movie_params)
  if @movie.save
    redirect_to @movie
  else
    render 'new'
  end
end

private

def movie_params
  params.require(:movie).permit(:title, :release_date, :plot, :song, :artist)
end

有人能告诉我在create / movie_params方法中需要哪些代码吗?或者如果我以完全错误的方式处理它,如果是这样,我应该如何实现它?

我正在使用Rails 5.1.4

2 个答案:

答案 0 :(得分:0)

您需要使用的是accepts_nested_attributes_for,它允许您在theme_song表单中使用movie的嵌套表单:

将其添加到您的Movie型号:

class Movie < ApplicationRecord
  has_one :theme_song

  accepts_nested_attributes_for :theme_song
end
电影控制器中的

def new
  @movie = Movie.new
  @movie.build_theme_song
end

private

def movie_params
  params.require(:movie).permit(:title, :release_date, :plot, :song, :artist, theme_song_attributes: [:song, :artist])
end

最后,在movie表单中使用fields_for帮助器为电影theme_song添加字段:

<%= form_for @movie do |f| %>
  theme song:
  <ul>
  <%= f.fields_for @movie.theme_song do |theme_song_form| %>
    <li>
    <%= theme_song_form.label :song %>
    <%= theme_song_form.text_field :song %>
    ...
    </li>
  <% end %>
 </ul>
<% end %>

现在,当您提交表单时,它会为该电影创建movie条记录和theme_song记录。

答案 1 :(得分:0)

没有为theme_song模型提供信息,需要创建哪些字段或哪些数据,但您可能不希望这两个表中的数据重复。

您没有采用错误的方式,将两组数据添加到单个表单可能最简单,使用accepts_nested_attributes。然后告诉你的movies_controller参数也接受嵌套特征。然后它以魔术方式以相应的方式保存数据。

1将嵌套选项添加到电影模型

class Movie < ApplicationRecord
  has_one :theme_song 
  accepts_nested_attributes_for :theme_song
end

2将表格嵌套在一起<​​/ h1>
<%= form_with model: @movie, local: true do |form| %>
  <p><strong>Movie Details</strong></p>
  <p>
    <%= form.label 'Title:' %>
    <%= form.text_field :title %>
  </p>
  <p>
    <%= form.label 'Release date:' %>
    <%= form.text_field :release_date %>
  </p>
  <p>
    <%= form.label 'Plot:' %>
    <%= form.text_area :plot %>
  </p>
  <p><strong>Soundtrack</strong></p>
  <%= form.fields_for :theme_song do |theme_song| %>
    <p>
      <%= theme_song.label 'Theme song:' %>
      <%= theme_song.text_area :song %>
    </p>
    <p>
      <%= theme_song.label 'Artist:' %>
      <%= theme_song.text_area :artist %>
    </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

3更新控制器参数+创建新对象

def create
  @movie = Movie.new(movie_params)
  if @movie.save
    redirect_to @movie
  else
    render 'new'
  end
end

def new
  @movie = Movie.new
  @movie.build_theme_song
end
private

def movie_params
  params.require(:movie).permit(:title, :release_date, :plot, :song, :artist, theme_song_attributes: [:song, :artist, :id])
end

这里要注意两件事,第一件事是在新操作中你需要确保构建嵌套记录。其次,嵌套属性以数组的形式添加到参数中,它必须是这样的。

的SideNote

使用此方法有其局限性。您应该知道这意味着如果两部不同的电影使用相同的主题曲,您将拥有2首电影唱片和2首主题曲唱片。这可能会让它更慢/更难说'#34;向我展示这首歌所在的所有电影&#34;,因为那时你必须考虑用户错误和按名称搜索的拼写。您可能会发现,在将来,最好有一个电影记录,一个主题歌曲记录和一个MovieThemeSongs记录,它基本上加入了这两个记录。