2011-04-19 3 views
1

내 사용자 모델을 프로필 accept_nested_attributes_로 변경했으며 동시에 사용자 및 프로필을 만들려고합니다. 저는 Devise를 인증에 사용하고 있습니다.레일 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]il.com', '$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

당신은 Profile 모델의 save_user 콜백이 필요하지 않습니다.

user.save을 실행하면 자동으로 user.profile을 저장합니다. 콜백으로 인해 user.profile이 저장되고 다시 저장하라는 사용자가 호출됩니다. 그리고 사용자가 저장하면 프로필도 저장됩니다 ......

그건 루프입니다.

그래서 가장 간단한 수정은 프로필 모델에서 after_update 콜백을 제거하는 것입니다.

프로필 만 저장하려면 profile.save을 사용하십시오. 사용자 개체에도 업데이트가있는 경우 user.save 또는 profile.user.save을 사용하십시오.

+0

그래, 그게 다야. 문제는 이것입니다 : 누군가가 자신의 프로필을 변경할 때마다 트리거되기를 원하는 User 콜백이 있습니다. 프로파일에서'after_update' 콜백이 없으면 다른 방법으로 설정하여 자식이 저장되면 (프로파일) 부모도 저장됩니다 (사용자) - 역방향 (자동으로 발생)이 아닌? – Andrew

+0

프로필을 업데이트하는 동안 사용자를 저장해야하는 이유는 무엇입니까? 사용자 개체를 변경하지 않은 이유는 무엇입니까? 왜 저장해야합니까? – PeterWong

+0

사용자 모델에 연결했지만 사용자 프로필의 일부 정보를 사용하는 제 3 자 API 콜백 등이 있습니다. API 후크를 복제하거나 해당 메소드를 공개하지 않고 사용자 모델이 저장 될 때 자동으로 실행하므로 사용자를 호출하는 것이 가장 쉽습니다. 그 문제를 해결할 수있는 또 다른 방법이 있다면 나는 단지 궁금했다. – Andrew