2013-05-20 4 views
8

I две модели User и Submission следующим образом:first_or_create по электронной почте, а затем сохранить вложенной моделируют

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 

У меня есть форма, которая собирает данные, необходимые для этих двух моделей. Пользовательский контроллер:

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 

Что я хочу сделать, это сначала проверить, существует ли пользователь в системе по электронной почте. Если это так, я хочу создать представление для этого пользователя. В противном случае создайте пользователя и отправьте его одновременно.

Я смущен, как это сделать с помощью метода first_or_create.

Любая помощь приветствуется.

ответ

13

first_or_createaccepts a block. Таким образом, вы могли бы сделать это следующим образом:

@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

Я должен «слить» вместо того, чтобы назначать ему, но это мое личное предпочтение. Очиститель немного. –

+0

Спасибо, что это самый чистый ответ. – chell

+0

create вызывается только в том случае, если пользователь еще не существует в базе данных. Я обнаружил, что это создало проблему, потому что она не создавала объект отправки, если пользователь уже существует. – chell

-3

Эй, я думаю, что это должно быть что-то вроде этого

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

Тогда в пользовательской модели

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) существует в ActiveRecord уже. Вы не должны писать свои собственные. – Mischa

+0

Если пользователь не существует, этот код не создает представления. – davogones

1

Поскольку ваш случай использования является немного более сложным, оно не может повредить, чтобы разделить это вверх в два отдельных действия. Если вы хотите, чтобы это произошло атомарно, вы можете выбросить его в transaction.

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

Зачем мне это делать как транзакцию? Сможет ли это создать объект отправки? – chell

+0

Я предполагаю, что ваши параметры выглядят как '{user: ..., submissions_attributes: {...}}', так как у вас есть 'accepts_nested_attributes_for: submissions_attributes' в вашей модели. Связанная модель автоматически создаётся, если вы вставляете атрибуты представления. Транзакция гарантирует, что все будет создано/обновлено атомарно (т. Е. Либо все успешно, либо все возвращается). – davogones

+0

Мне тоже нравится этот ответ. Я NOOB и не уверен, что лучший ответ. Я пошел с одним из RDX, потому что он просто использовал один метод. – chell

Смежные вопросы