2011-04-19 1 views
1

Я изменил модель User на accept_nested_attributes_for Profile, и я пытаюсь одновременно создать пользователя и профиль. Я использую Devise для аутентификации.Rails 3: Бесконечный SQL-запрос?

Это, кажется, работает - за один гигантский Гоча кроме ...

Каждый раз, когда я создаю нового пользователя он выходит из строя приложение с «нелегальной инструкцией», и когда я проверяю журнал, это выглядит следующим образом ...

Started POST "/users" for 127.0.0.1 at 2011-04-18 21:01:54 -0500 
    Processing by UsersController#create as HTML 
    Parameters: {"utf8"=>"‚úì", "authenticity_token"=>"Rua6PUxnE4a4TvaFcVMfmycw8Y9AFRjEsXVrqwWC2EM=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "profile_attributes"=>{"first_name"=>"Name", "last_name"=>"Tester"}, "student_claimed"=>"false", "school"=>"", "invite_code"=>"Texas!", "terms_of_service"=>"1"}, "commit"=>"Create Account!"} 
    [1m[35mSQL (0.3ms)[0m SELECT name 
FROM sqlite_master 
WHERE type = 'table' AND NOT name = 'sqlite_sequence' 
    [1m[36mSQL (0.3ms)[0m [1m SELECT name 
FROM sqlite_master 
WHERE type = 'table' AND NOT name = 'sqlite_sequence' 
[0m 
    [1m[35mUser Load (0.2ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) LIMIT 1 
    [1m[36mInvitation Load (0.1ms)[0m [1mSELECT "invitations".* FROM "invitations" WHERE "invitations"."code" = 'Texas!' LIMIT 1[0m 
    [1m[35mUser Load (0.1ms)[0m SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'duALIT6yCL5ShpMvbw79' LIMIT 1 
    [1m[36mRole Load (0.3ms)[0m [1mSELECT "roles".* FROM "roles" WHERE "roles"."name" = 'member' LIMIT 1[0m 
    [1m[35mAREL (0.3ms)[0m UPDATE "invitations" SET "remaining_uses" = 9993, "updated_at" = '2011-04-19 02:01:54.506243' WHERE "invitations"."id" = 1 
    [1m[36mAREL (0.2ms)[0m [1mINSERT INTO "users" ("email", "encrypted_password", "reset_password_token", "remember_token", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "created_at", "updated_at", "plan_code", "confirmation_token", "confirmed_at", "confirmation_sent_at", "student_claimed", "student_confirmed", "school", "invitation_id") VALUES ('[email protected]', '$2a$10$7qzC7T6b1kLiXvPSkMRkduCFClBznDWnnOu7I1ssU8blB9NMJznn2', NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, '2011-04-19 02:01:54.509656', '2011-04-19 02:01:54.509656', NULL, 'duALIT6yCL5ShpMvbw79', NULL, '2011-04-19 02:01:54.437796', 'f', 'f', '', 1)[0m 
    [1m[35mSQL (0.1ms)[0m INSERT INTO "roles_users" ("role_id", "user_id") VALUES (3, 6) 
Rendered devise/mailer/confirmation_instructions.html.erb (0.9ms) 

Sent mail to [email protected] (1966ms) 
Date: Mon, 18 Apr 2011 21:01:55 -0500 
From: __________ 
Reply-To: ___________ 
To: _____________ 
Message-ID: <[email protected]> 
Subject: Please confirm your email address 
Mime-Version: 1.0 
Content-Type: text/html; 
charset=UTF-8 
Content-Transfer-Encoding: 7bit 

<p>Name,</p> 

<p>You registered with the email address: [email protected] You can confirm your account through the link below:</p> 

<p><a href="http://localhost:3000/users/confirmation?confirmation_token=duALIT6yCL5ShpMvbw79">Confirm my account</a></p> 

<p>Thanks for signing up!</p> 

    [1m[36mAREL (0.2ms)[0m [1mINSERT INTO "profiles" ("first_name", "last_name", "created_at", "updated_at", "user_id", "avatar_file_name", "avatar_content_type", "avatar_file_size", "avatar_updated_at", "address1", "city", "state", "country", "zip") VALUES ('Name', 'Tester', '2011-04-19 02:01:57.266502', '2011-04-19 02:01:57.266502', 6, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)[0m 
[paperclip] Saving attachments. 
    [1m[35mUser Load (0.1ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) AND ("users".id <> 6) LIMIT 1 
    [1m[36mUser Load (1.6ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m 
    [1m[35mProfile Load (1.6ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6) 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) AND ("users".id <> 6) LIMIT 1[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) AND ("users".id <> 6) LIMIT 1 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6) 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) AND ("users".id <> 6) LIMIT 1[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]')) AND ("users".id <> 6) LIMIT 1 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m 
    [1m[35mCACHE (0.0ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6) 

    ... and so on for about 100 more lines ... 

    [1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1 
    [1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m 
    [1m[36mSQL (0.3ms)[0m [1m SELECT name 

Таким образом, это не происходит, прежде чем я начал принимать вложенные атрибуты ... и я очень смущен, почему это происходит сейчас. Кто-нибудь знает, как отладить это и устранить проблему?

Спасибо!

--EDIT--

пользователя Модель:

class User < ActiveRecord::Base 
    # RELATIONSHIPS 
    has_one :profile, :dependent => :destroy 
    has_many :photos 
    has_many :votes 
    has_many :voted_photos, :through => :votes, :source => :photo 
    has_many :ratings 
    has_many :rated_photos, :through => :ratings, :source => :photo 
    has_many :comments 
    has_and_belongs_to_many :roles 
    has_many :assignments 
    has_many :collections, :through => :assignments 
    belongs_to :invitation 

    accepts_nested_attributes_for :profile 

    # VIRTUAL ATTRIBUTES 
    attr_accessor :invite_code 

    # AUTHENTICATION 
    devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :confirmable 

    # SECURITY 
    attr_accessible :email, :password, :password_confirmation, :remember_me, :confirmed_at, :invite_code, :student_claimed, :school, :terms_of_service, :profile_attributes 

    # FILTERS 
    before_create :set_role_to_member, :set_invitation 
    after_save :update_recurly_account, :unless => Proc.new { Rails.env.test? } 

    # VALIDATIONS 
    validates_acceptance_of :terms_of_service, :message => "You must agree to the terms of service in order to create an account." 
    validate :invitation_status, :on => :create 
    validates_presence_of :profile 
    validates_associated :profile 

    # DELEGATES 
    delegate :first_name, :last_name, :full_name, 
      :to => :profile, 
      :allow_nil => true 

    # ROLES 
    def set_role_to_member 
    self.roles << Role.find_by_name('member') 
    end 

    def has_role?(r) 
    !roles.find_by_name(r).nil? 
    end 

    def list_roles 
    list = [] 
    roles.all.each do |r| 
     list << r.name 
    end 
    list.join(', ') 
    end 

    # DEVISE RELATED 
    # Hook up recurly account after confirmation 
    def confirm! 
    self.setup_recurly_account unless Rails.env.test? 

    if student_claimed && validate_student_email 
     self.student_confirmed = true 
     self.save 
    end 

    super 
    end 

    protected 
    # Don't require password on update 
    def password_required? 
    !persisted? || password.present? || password_confirmation.present? 
    end 

    public 

    # RECURLY RELATED 

    def setup_recurly_account 
    ... 
    end 

    private 

    def update_recurly_account 
     ... 
    end 

    def validate_student_email 
     self.email =~ /\.edu$/ ? true : false 
    end 

    def invitation_status 
     ... 
    end 

    def set_invitation 
     ... 
    end 

end 

Профиль Модель

class Profile < ActiveRecord::Base 
    include Helpers::AssetStorage 

    # RELATIONSHIPS 
    belongs_to :user 

    stores_file_as :avatar, 
        :styles => { :tenth => "87x87#", :eighth => "106x106#" }, 
        :filename_interpolation => "avatars/:user_id/:id_:style.:extension", 
        :default_url => '/images/no_avatar_:style.png' 

    # VALIDATIONS 
    validates_presence_of :first_name, :last_name 

    # CALLBACKS 
    after_update :save_user 

    def full_name 
    [first_name,last_name].join(" ") 
    end 

    private 

    def save_user 
     self.user.save! 
    end 

end 
+0

Нам нужно увидеть ваши модели. – smathy

+0

Добавлено. См. Выше. – Andrew

ответ

1

Вам не нужно save_user обратного вызова для Profile модели.

Выполнение user.save, оно автоматически сэкономит user.profile. Из-за обратного вызова user.profile сохранен, и он вызывает его повторное сохранение. И пользователь сохраняет, он также сохраняет свой профиль ......

Это петля.

Таким образом, самым простым вариантом было бы удалить обратный вызов after_update в модели профиля.

Для того, чтобы сохранить профиль, используйте только profile.save. Если пользовательский объект также имеет обновления, используйте user.save или profile.user.save.

+0

Да, все. Проблема в том, что в модели User есть некоторые обратные вызовы, которые я хочу запускать, когда кто-то вносит изменения в свой профиль. Без обратного вызова 'after_update' в Профиле есть какой-либо другой способ его настройки, чтобы, если дочерний элемент был сохранен (профиль), родитель также сохраняется (пользователь) - не только наоборот (что происходит автоматически)? – Andrew

+0

Зачем вам нужно сохранять пользователя, пока у вас есть только обновления профиля? Я имею в виду, что у вас нет каких-либо изменений в пользовательском объекте, почему вам нужно его сохранить? – PeterWong

+0

Есть некоторые сторонние обратные вызовы API и т. Д., Которые я подключил к модели User, но они используют некоторую информацию из профиля пользователя. Я не хочу дублировать крючки API и не публиковать эти методы, и они автоматически запускаются при сохранении модели пользователя, поэтому проще всего запустить их, чтобы вызвать пользователя. Я могу обойти это, мне было просто любопытно, есть ли другой способ вызвать их. – Andrew

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

  • Нет связанных вопросов^_^