我正在尝试使用 Rails 4.0.0 作为学习项目制作一个简单的电影数据库。我对尽可能多地使用脚手架特别感兴趣,因为这是最初吸引我使用 RoR 的功能之一。
是的,我确实意识到潜在的风险(方框 1.2.Scaffolding:更快、更容易、更诱人),但我保证在我真正了解幕后发生的事情之前,我不会让我的项目公开。现在我更多的是在“为我的下一个超级骗子项目评估技术”模式。
这是我到目前为止所得到的:
rails g scaffold Person name:string
rails g scaffold Movie name:string
现在,我可以做类似的事情
rails g scaffold Movie name:string person_id:integer
相反,但我希望一部电影同时与导演和演员相关联。(下一步是建立一个关联,将多个演员与一部电影联系起来,但我还没有完全做到。)
因此,我前往博客文章使用同一张表创建多个关联,描述了我所需要的内容。这是一个有点旧的帖子,所以现在情况可能已经改变了——我不知道。反正。这就是我改变模型的方式:
class Person < ActiveRecord::Base
has_many :movies
end
和
class Movie < ActiveRecord::Base
belongs_to :director_id, :class_name => 'Person', :foreign_key => 'person_id'
belongs_to :actor_id, :class_name => 'Person', :foreign_key => 'actor_id'
end
最后是神奇的
rake db:migrate
通过在控制台中运行启动 WEBrick rails s
,我打开浏览器并开始注册人员
是时候开始注册电影了。根据此处和此处的先前问题,我必须制作一个迁移脚本才能创建必要的数据库字段。所以这就是我所做的:
rails g migration AddPersonIdsToMovies director_id:integer actor_id:integer
我也更新app/views/movies/_form.html.erb
了
<%= form_for(@movie) do |f| %>
<% if @movie.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@movie.errors.count, "error") %> prohibited this movie from being saved:</h2>
<ul>
<% @movie.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :director_id %><br>
<%= f.select :director_id, Person.all.collect {|x| [x.name, x.id]}, {}, :multiple => false %>
</div>
<div class="field">
<%= f.label :actor_id %><br>
<%= f.select :actor_id, Person.all.collect {|x| [x.name, x.id]}, {}, :multiple => false %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
当我创建一个新电影时,视图显示正常,选择输入工作正常。但是,director 和 actor 字段中的数据不会被持久化。我跑过去rails console
看了看新制作的电影:
irb(main):004:0> mov = Movie.first
Movie Load (0.2ms) SELECT "movies".* FROM "movies" ORDER BY "movies"."id"
ASC LIMIT 1 => #<Movie id: 1, name: "No such movie", created_at:
"2013-08-02 17:02:12", updated_at: "2013-08-02 17:02:12",
director_id: nil, actor_id: nil>
没有导演或演员信息,这有点令人失望。
更新
根据@Mattherick 的建议,我将私有部分编辑为movies_controller.rb
:
# Never trust parameters from the scary internet, only allow the white list through.
def movie_params
params.require(:movie).permit(:name, :director_id, :actor_id)
end
不幸的是,当我发布新电影时,我得到
人(#70319935588740)预期,得到字符串(#70319918738480)
提取来源:
# POST /movies.json def create @movie = Movie.new(movie_params) respond_to do |format| if @movie.save
请求数据如下
{"utf8"=>"✓", "authenticity_token"=>"???", "movie"=>{"name"=>"浪漫喜剧", "director_id"=>"2", "actor_id"= >"1"}, "commit"=>"创建电影"}
更新 2
我试图在 Rails 控制台中创建一个新电影,如下所示:
irb(main):001:0> movie = Movie.new(name: "My fine movie", director_id: "1", actor_id: "2")
ActiveRecord::AssociationTypeMismatch: Person(#70311109773080) expected, got String(#70311102311480)
这是您对 POST 到控制器的期望。director_id
这让我测试了如果我排除了and的引号会发生什么actor_id
。所以我做了
irb(main):005:0> movie = Movie.new(name: "My fine movie", director_id: 1, actor_id: 2)
ActiveRecord::AssociationTypeMismatch: Person(#70282707507880) expected, got Fixnum(#70282677499540)
还在用控制台,我决定创建一个演员和一个导演
director = Person.new(name: "Woody Allen")
director.save
actor = Person.new(name: "Arnold Schwarzenegger")
actor.save
然后我做了
movie = Movie.new(name: "I'd like to see that", director_id: director, actor_id: actor)
movie.save
它就像一个魅力(为简洁起见省略了输出)。所以整个问题归结为“如何将 Person 作为参数传递给director_id
和actor_id
通过 Web 界面?”
如果我在 Movies 中有一个名为 的字段person_id: integer
,我相信 rails 会推断出我不是试图传递包含人的 id 的字符串,而是我试图传递整个人对象。
更新 3
我测试了我的怀疑,即当外键列以模式 [table]_id 命名时,rails 理解如何处理帖子。所以我创建了一个带有Continent
模型和Country
模型的新项目,其中rails g scaffold Country name:string continent_id:integer
. 我改变了我的Country
看法,包括
<div class="field">
<%= f.label :continent_id %><br>
<%= f.select :continent_id, Continent.all.collect {|x| [x.name, x.id]} %>
</div>
而不是默认的数字字段。continent_id
仍然发布了一个字符串:
Started POST "/countries" for 127.0.0.1 at 2013-08-03 10:40:40 +0200
Processing by CountriesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"???", "country"=>{"name"=>"Uganda", "continent_id"=>"4"}, "commit"=>"Create Country"}
然而,rails 明白这continent_id
是表中条目的标识符Continent
。
可悲的是,推断器机制在我原来的情况下不起作用,因为我有两个从表Movie
到Person
表的关联。我需要以某种方式确保 rails 了解存在从director_id
到 a的映射Person
。
更新 4
根据一些消息来源,我似乎需要Person
进一步完善模型。所以我做了
class Person < ActiveRecord::Base
has_many :directed_movies, :class_name => 'Movie', :foreign_key => 'director_id'
has_many :acted_movies, :class_name => 'Movie', :foreign_key => 'actor_id'
end
但仍然没有解决我的问题。
我有点迷路了。谁能给我一些关于我在这里缺少的东西的指示?谁能帮我映射从director_id
到person_id
?谢谢!