2013-05-20 20 views
8

Ben iki model User ve Submission kaydedin:e-posta ile first_or_create ve ardından iç içe modeli

class User < ActiveRecord::Base 
    # Associations 
    has_many :submissions 
    accepts_nested_attributes_for :submissions 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :name, :role, :submission_ids, :quotation_ids, :submissions_attributes 

    validates :email, :presence => {:message => "Please enter a valid email address" } 
    validates :email, :uniqueness => { :case_sensitive => false } 
end 

class Submission < ActiveRecord::Base 
    belongs_to :user 
    attr_accessible :due_date, :text, :title, :word_count, :work_type, :rush, :user, :notes 

    validates :work_type, :title, :text,:presence => true 
    validates :text, :length => { :minimum => 250 } 
    validates :word_count, :numericality => { :only_integer => true } 
end 

Ben bu iki model tarafından gerekli verileri toplayan bir form var. Kullanıcılar kontrolörü: Ne yapmak istediğim ilk kontroldür

def index 
    @user = User.new 
    @user.submissions.build 
end 

def create 
    @user = User.where(:email => params[:user][:email]).first_or_create(params[:user]) 

    if @user 
    redirect_to :root 
    else 
    render 'pages/index' 
    end 
end 

kullanıcı daha önce gönderilen e-posta ile sistemde varsa. Öyleyse o kullanıcı için bir gönderim oluşturmak istiyorum. Aksi takdirde, kullanıcı ve gönderimi aynı anda oluşturun.

first_or_create yöntemiyle bunun nasıl yapılacağı konusunda kafam karıştı.

Herhangi bir yardım için teşekkür ederiz.

cevap

13

first_or_createaccepts a block. aşağıdaki gibi Yani bunu yapabilirdi:

@user = User.where(:email => params[:user][:email]).first_or_create do |user| 
    # This block is called with a new user object with only :email set 
    # Customize this object to your will 
    user.attributes = params[:user] 
    # After this, first_or_create will call user.create, so you don't have to 
end 
+0

Ona atama yerine birleştirme yapmalıyım, ama bu benim kişisel tercihim. Temizleyici biraz. –

+0

Bu en temiz cevap – chell

+0

yarattığınız için teşekkürler, kullanıcı veritabanında zaten yoksa, yalnızca çağrılır. Kullanıcının zaten mevcut olduğunda gönderim nesnesini oluşturmayacağı için bir sorun yarattığını buldum. – chell

-3

Hey Kullanım durumunuz, bu içine bu kadar bölünmüş bir zararı olmayabilir biraz daha karmaşık olduğu için bu Ardından kullanıcı modeli

def first_or_create(params) 
    unless user = User.where(:email => params[:email]).first # try to find user 
    user = User.create(email: params[:user]) 
    # it should create also submission because of accepts_nested_attributes_for 
    else #user exsists so we need to create submission for him 
    user.submissions.create(params[:submissions]) 
    end 
end 
+1

[ 'first_or_create'] (http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-first_or_create) zaten ActiveRecord bulunmaktadır. Kendi yazman olmamalı. – Mischa

+0

Kullanıcı yoksa, bu kod gönderimleri oluşturmaz. – davogones

1

o

@user = User.first_or_create(params[:user]) 

gibi bir şey olması gerektiğini düşünüyorum iki ayrı eylem. Bunun atomik olarak gerçekleşmesini istiyorsanız, onu transaction'a atabilirsiniz.

User.transaction do 
    # Create the user if they don't already exist 
    @user = User.where(:email => params[:user][:email]).first_or_create 

    # Update with more attributes, and create nested submissions 
    @user.update_attributes(params[:user]) 
end 
+0

Bunu neden bir işlem olarak yapabilirim? Bu, gönderim nesnesini de oluşturacak mı? – chell

+0

Paranormalleriniz, modelinizde "accepts_nested_attributes_for: submissions_attributes" olduğundan beri, {user: ..., submissions_attributes: {...}} 'gibi görünüyor. Gönderme niteliklerini yerleştirirseniz, ilgili model otomatik olarak oluşturulur. İşlem, her şeyin atomik olarak oluşturulmasını/güncellendiğinden emin olacaktır (yani, hepsi başarılı veya tüm rulolar geri döner). – davogones

+0

Bu cevabı da beğeniyorum. Ben bir NOOB'um ve hangisinin en iyi cevap olduğuna emin değilim. RDX'den biriyle gittim çünkü sadece bir yöntem kullandı. – chell