3

2 つの既存のモデルの間に特別な関係を作成しようとしていUserますDwelling。Aは、作成時にDwelling1 人の所有者 ( Dwelling belongs_to :user、 ) しか持っていません。User has_one :dwellingただし、他のユーザーをこれに追加することができますDwelling(Roomies現在、このために作成されたモデルはなくRoomie、概念的な関係です)。

別のモデルが必要だとは思いませんが、既存のモデルとの特別な関係が必要だと思いますが、間違っている可能性があります。user_id参照は表から行う必要があると思いUsersます。どこから始めればよいかよくわかりません。助けてくれてありがとう!

例えば:

Dwelling1 
  user_id: 1 
  roomies: [1, 2, 3, 4]

1、2、3、4 は user_id です。

更新されたモデル

Dwelling Model

# dwelling.rb
class Dwelling < ActiveRecord::Base
    attr_accessible :street_address, :city, :state, :zip, :nickname

    belongs_to :owner, :class_name => "User", :foreign_key => "owner_id"
    has_many :roomies, :class_name => "User"

    validates :street_address, presence: true
    validates :city, presence: true
    validates :state, presence: true
    validates :zip, presence: true

end

User Model

# user.rb
class User < ActiveRecord::Base
  attr_accessible :email, :first_name, :last_name, :password, :password_confirmation, :zip
  has_secure_password

  before_save { |user| user.email = email.downcase }
  before_save :create_remember_token

  belongs_to :dwelling
  has_many :properties, :class_name => "Dwelling", :foreign_key => "owner_id"

  validates :first_name, presence: true, length: { maximum: 50 }
  ...

Updated Dwelling Create Action

#dwellings_controller.rb
...
def create
@dwelling = current_user.properties.build(params[:dwelling])

  if @dwelling.save
    current_user.dwelling = @dwelling
    if current_user.save
      flash[:success] = "Woohoo! Your dwelling has been created. Welcome home!"
      redirect_to current_user
    else
      render 'new'
    end
  end
end
...
4

3 に答える 3

2

私の答えは、あなたがただ一つuserになりたいだけだと仮定しています。を複数で使用したい場合は、@ ariの答えは良いと思いますが、の代わりに選択することもできます。roomiedwellinguserroomiedwellinghas_and_belongs_to_manyhas_many :through

今私の答えのために:

belongs_to私はそれを所有者とhas_many部屋(おそらく所有者を含むが必ずしもそうではない)の住居になるように設定しました。

とのUser両方のモデルを使用できます。追加のテーブルやモデルは必要ありません。オプションを使用して適切な関係を設定するだけです。ownersroomies:class_name:foreign_key

モデルDwelling内:

# dwelling.rb
belongs_to :owner, :class_name => "User", :foreign_key => "owner_id"
has_many :roomies, :class_name => "User"

モデルUser内:

# user.rb
belongs_to :dwelling # This is where the user lives
has_many :properties, :class_name => "Dwelling", :foreign_key => "owner_id"  # This is the dwellings the user owns

テーブルには、所有者のを格納するための列dwellingsが必要ですowner_iduser_id

テーブルには、ユーザーが住んでいる住居を保存usersする必要があります。dwelling_iddwelling_id

コントローラに関するコメントであなたの質問に答えるには:

current_user新しい住居の所有者として設定する場合は、次のようにします。

@dwelling = current_user.properties.build(params[:dwelling])
....

current_user新しい住居の所有者および部屋の所有者として設定する場合は、次のようにします。

@dwelling = current_user.properties.build(params[:dwelling]

if @dwelling.save
  current_user.dwelling = @dwelling
  if current_user.save
     # flash and redirect go here        
  else
     # It's not clear why this wouldn't save, but you'll to determine
     # What to do in such a case.
  end
else
   ...
end

上記の最も難しい部分は、住居が有効で保存されている場合を処理することですが、何らかの無関係な理由current_userで保存できません。アプリケーションによっては、ルーミーとして割り当てることができない場合でも、とにかく住居を保存したい場合がありますcurrent_user。または、住居を保存しないようにすることもできます。保存する場合は、モデルトランザクションを使用する必要がありますが、これはこの質問の範囲を少し超えています。

current_userDwellingを保存しても実際にはレコードが更新されて保存されないため、コントローラーコードは機能しませんでしたdwelling_id。コードは次のようになります。

@dwelling = Dwelling.new(params[:dwelling])
current_user.dwelling = @dwelling
if @dwelling.save
   ...

current_userそれは決して保存されないので、そのcurrent_user.dwelling = @dwelling行は役に立たないことに注意してください。

これは直感に反しているように見えるかもしれませんが、肝心なのは、build_dwelling期待どおりに実際にメモリに設定されていないということです。構築しているモデルではなく、構築ているモデルを保存すると、より直感的な結果が得られます。

@dwelling = current_user.build_dwelling(params[:dwelling])
if current_user.save # This will save the dwelling (if it is valid)

ただし、これは(デフォルトで)検証エラーがある場合:autosave、関連付けをオンにしない限り住居を保存しません。これもこの質問の範囲を少し超えています。私は本当にこのアプローチをお勧めしません。

アップデート:

より詳細なコードスニペットは次のとおりです。**

# dwellings_controller.rb

def create
  @dwelling = current_user.properties.build(params[:dwelling])

  if @dwelling.save
    # The current user is now the owner, but we also want to try to assign
    # his as a roomie:
    current_user.dwelling = @dwelling
    if current_user.save
      flash[:notice] = "You have successfully created a dwelling"
    else
       # For some reason, current_user couldn't be assigned as a roomie at the 
       # dwelling.  This could be for several reasons such as validations on the
       # user model that prevent the current_user from being saved.
       flash[:notice] = "You have successfully created a dwelling, but we could not assign you to it as a roomie"
    end
    redirect_to current_user
  else
    # Dwelling could not be saved, so re-display the creation form:
    render :new
  end
end

住居が正常に保存されると、現在のユーザーが(owner_idデータベース内の)所有者になります。ただし、current_userが保存されない場合は、アプリケーションがそれにどのように応答するかを決定する必要があります。上記の例では、住居を保存することを許可していますが(つまり、作成をロールバックしません)、ユーザーに部屋を割り当てることができなかったことを通知します。これが発生した場合、問題の原因はアプリケーション内の他のコードである可能性があります。のエラーを調べて、そのcurrent_user理由を確認できます。current_user.save!または、一時的にではなく、を使用current_user.saveしてトラブルシューティングを行うこともできます。

これをすべて行う別の方法は、モデルafter_createでコールバックを使用することです。Dwelling多くの点で、それはよりクリーンで簡単な方法です。ただし、current_user保存できない場合のケースのキャッチは、処理方法によっては、上記の方法よりもさらに醜い場合があります。

肝心なのは、current_user.saveコードがいくつかの問題を引き起こしているということだと思います。その理由を診断し、その場合にアプリケーションが何をすべきかを判断する必要があります。これを処理するには、少なくとも次のようないくつかの方法があります。

  1. すべてをトランザクションブロックに入れ、current_use.save!代わりにを使用current_user.saveして、例外が発生し、ユーザーも住居も保存されないようにします。
  2. 住居を保存しますが、彼は部屋の人ではないことをユーザーに知らせます(上記のように)
  3. current_userを保存する代わりに、を使用しますupdate_column(これにより、コールバックや検証などが回避されます)。

あなたが経験している現在の問題は、本質的に元の質問とは無関係であると私は信じています。さらに支援が必要な場合は、別の質問としてそれを中断するのが最善かもしれません。

于 2012-08-03T02:12:39.313 に答える
1

2 つの選択肢があります。計画によっては、所有者が 1 つの住居を所有するよりも、住居が所有者を 1 つ持つ方が明確な場合があります。そうすれば、住居もユーザーを持つことができるでしょう。Dwelling_id という名前の User に列を追加すると、dwelling has_many users を実行できます。

別のオプションは、「has_many through」関連付けを使用することです。つまり、この関連付けを追跡する新しいモデル、たとえば「Relationship.rb」を作成する必要があります。このモデルは、User と Dwelling の両方に属します (両方の列があります)。次に、次のようなコードを記述できます。

//in Dwelling.rb
has_many :roomies, through: :relationships, source: :user

//in User.rb
has_many :dwellings, through: :relationships

これにより、ユーザーは複数の住居に参加することもできます。

于 2012-08-02T14:38:35.140 に答える
1

これを行うには、Roomie id を Dwelling の列として保存します。

移行を行います。

class AddRoomiesToDwelling < ActiveRecord::Migration
  def self.up
    add_column :dwelling, :roomies, :text
  end

  def self.down
    remove_column :dwelling, :roomies
  end
end

住居モデルで:

class Dwelling < ActiveRecord::Base
  serialize :roomies
end

次に、次の方法でルーム ID を設定できます。

roomie_ids = [1, 2, 3, 4]  
@dwelling.roomies = {:ids => roomie_ids}
@dwelling.save!

このセクションの「テキスト列に配列、ハッシュ、およびその他のマッピング不可能なオブジェクトを保存する」セクションから抜粋

于 2012-08-02T14:43:21.730 に答える