1

Rails 4.0.0 を学習プロジェクトとして使用して、簡単な映画データベースを作成しようとしています。そもそも私が RoR に惹かれた機能の 1 つであるため、可能な限りスキャフォールディングを使用することに特に関心があります。

はい、私は潜在的なリスクを認識しています(Box 1.2.足場: より迅速に、より簡単に、より魅惑的に)、しかし、内部で何が起こっているかを本当に理解するまで、プロジェクトを公開しないことを約束します。現在、私は「次の超大型プロジェクトのための技術を評価している」モードになっています。

ここに私がこれまでに持っているものがあります:

rails g scaffold Person name:string
rails g scaffold Movie name:string

今、私は次のようなことをすることができました

rails g scaffold Movie name:string person_id:integer

代わりに、映画を監督と俳優の両方に関連付けたいと考えています。(次のステップは、複数の俳優を 1 つの映画に関連付ける関連付けを作成することですが、まだ十分ではありません。)

それで、私はブログ記事の作成に向かいました 同じテーブルで複数の関連付けを作成する 、必要なもののほとんどを説明しています。少し古い投稿なので、現在は変わっている可能性があります-わかりません。ともかく。これは私がモデルをどのように変更したかです:

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し、ブラウザを開いてユーザーの登録を開始します。

ここに画像の説明を入力

いよいよ動画登録開始です。以前の質問hereおよびhereによると、必要なデータベース フィールドを作成するために移行スクリプトを作成する必要があります。だからこれは私がやったことです:

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 %>

新しいムービーを作成すると、ビューが正常に表示され、選択入力が正常に機能します。ただし、ディレクターおよび俳優フィールドのデータは保持されません。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

残念ながら、新しい映画を投稿すると、

Person(#70319935588740) が期待され、String(#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

次のように、レールコンソールで新しいムービーを作成しようとしました:

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これにより、との引用符を除外するとどうなるかをテストしました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

これは魅力的に機能しました(簡潔にするために出力を省略しました)。したがって、質問全体は「どのようにすればWeb インターフェースdirector_idとの間で引数として Person を渡すことができますか?」ということになります。actor_id

ムービーに という単一のフィールドがあった場合person_id: integer、Rails は、人物の ID を含む文字列を渡そうとしているのではなく、人物オブジェクト全体を渡そうとしていると推測したと思います。

アップデート 3

外部キー列がパターン [table]_id にちなんで名付けられた場合、Rails は投稿の処理方法を理解しているのではないかという疑いをテストしました。Continentそこで、モデルとモデルをCountry使用して新しいプロジェクトを作成しましたrails g scaffold Country name:string continent_id:integerCountry含めるようにビューを変更しました

<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"}

それでもレールは、それがテーブルcontinent_id内のエントリの識別子であることを理解していました。Continent

Movie悲しいことに、テーブルに対して2 つの関連付けがあるため、元のケースでは推論メカニズムは機能しませんPersondirector_idからへのマッピングがあることをレールが理解していることをどうにかして確認する必要があり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か? ありがとう!

4

1 に答える 1

0

よし、やっと手に入れた。これが正しい方法だとは思いませんが、少なくとも問題は解決しました。update 2 で述べたようにMovie、irb でオブジェクトを作成できたので、「web インターフェースを介して、director_id と actor_id に引数として Person を渡すにはどうすればよいですか?」という質問をしました。

ここの場所のソースによると、レールはクラスメソッドhas_manyとクラスメソッドを理解する必要がありましたbelongs_to。しかし、私はそれを機能させることができないようです。

だから私はこのように読むためにcreateメソッドをハックしました:movies_controller.rb

def create
  director = Person.where(:id => movie_params[:director_id]).first
  actor = Person.where(:id => movie_params[:actor_id]).first
  @movie = Movie.new(name: movie_params[:name], director_id: director, actor_id: actor)

  respond_to do |format|
    if @movie.save
      format.html { redirect_to @movie, notice: 'Movie was successfully created.' }
      format.json { render action: 'show', status: :created, location: @movie }
    else
      format.html { render action: 'new' }
      format.json { render json: @movie.errors, status: :unprocessable_entity }
    end
  end
end

これは確かに私が望むほどエレガントではなく、RoR のやり方ではないと思います。残念ながら、私がこれまでに取り組んできたのはこれだけですが、Rails 4 を使用して同じモデルに複数の関連付けを作成できる人が他にいる場合は、ぜひお知らせください。:)

于 2013-08-05T19:40:25.187 に答える