Devise + Omniauth Twitter + Twitter Gem 更新属性

Devise + Omniauth Twitter + Twitter Gem updating attributes

我需要一些帮助。我使用 Devise 来设置我的 user 模型。一个user有很多accounts。一个 account 属于一个 user。我希望能够使用回调后从 Twitter API 获得的一些哈希值更新 account 的属性。据我所知,在 Twitter 回调之后,account 属性根本没有更新,它们仍然是 nil。我如何更新 account 以便它在 Twitter 回调后保留 uidtoken 等。这就是我一直在努力做的。 twitter_accounts_controller.rb

class TwitterAccountsController < ApplicationController
  def create
    @account = Account.find_or_create_from_auth_hash(auth_hash)
    @account.user = current_user
    redirect_to root_path
  end

  protected
  def auth_hash
    request.env['omniauth.auth']
  end
end


accounts_controller.rb
class AccountsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_account, only: [:edit, :update, :destroy, :show]

  def index
    @accounts = Account
    @user = current_user
  end

  def new
    @account = Account.new
  end

  def create
    @account = Account.new(account_params)
    @account.user = current_user

    if @account.save
      $twitter.update("@someone from Rails app on Heroku")
      flash[:success] = "Account succesfully created."
      redirect_to @account
    else
      flash.now[:warning] = "Oops, something went wrong!"
      render 'new'
    end
  end

  def show
  end

  def edit
  end

  def update
    if @account.update_attributes(account_params)
      flash[:success] = "Account changes succesfully commited."
    else
      render 'edit'
    end
  end

  def destroy
    if @account.destroy
      flash[:success] = "Account is gone!"
      redirect_to root_path
    end
  end

  private
  def account_params
    params.require(:account).permit(:account_name, :description, posts_attributes: [:tweet])
  end

  def set_account
    @account = Account.find(params[:id])
    rescue ActiveRecord::RecordNotFound
    flash[:danger] = "The account you are looking for doesn't even exist! "
    redirect_to accounts_path
  end
end

account.rb

class Account < ActiveRecord::Base
    before_save :capitalize_name

    belongs_to :user
    has_many :posts, dependent: :destroy

    accepts_nested_attributes_for :posts

    validates :account_name, :description, presence: :true

    default_scope { order('created_at DESC') }

    def self.find_or_create_from_auth_hash(auth_hash)
        account = where(provider: auth_hash.provider, uid: auth_hash.uid).first_or_create
        account.update_attributes(
            name: auth_hash.info.name,
            profile_image: auth_hash.info.image,
            token: auth_hash.credentials.token,
            secret: auth_hash.credentials.secret
        )
        account
    end

    private
    def capitalize_name
        self.account_name = self.account_name.split.map { |name| name.capitalize }.join(" ")
    end
end

schema.rb

ActiveRecord::Schema.define(version: 20160322001131) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "accounts", force: :cascade do |t|
    t.string   "account_name"
    t.string   "description"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.integer  "user_id"
    t.string   "provider"
    t.string   "uid"
    t.string   "token"
    t.string   "secret"
    t.string   "profile_image"
    t.string   "name"
  end

  add_index "accounts", ["user_id"], name: "index_accounts_on_user_id", using: :btree

  create_table "posts", force: :cascade do |t|
    t.text     "tweet"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "account_id"
  end

  add_index "posts", ["account_id"], name: "index_posts_on_account_id", using: :btree

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

  add_foreign_key "accounts", "users"
  add_foreign_key "posts", "accounts"
end

user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :accounts
end

Heroku 控制台在回调后显示这些 nil 属性。

irb(main):013:0> Account.first
  Account Load (1.2ms)  SELECT  "accounts".* FROM "accounts"  ORDER BY created_at DESC LIMIT 1
  Account Load (1.2ms)  SELECT  "accounts".* FROM "accounts"  ORDER BY created_at DESC LIMIT 1
=> #<Account id: 7, account_name: "Fadsa Adafda", description: "adfasdf", created_at: "2016-03-22 01:29:47", updated_at: "2016-03-22 01:29:47", user_id: 1, provider: nil, uid: nil, token: nil, secret: nil, profile_image: nil, name: nil>

在您的 Account 模型中,您有以下内容:

validates :account_name, :description, presence: :true

def self.find_or_create_from_auth_hash(auth_hash)
  account = where(provider: auth_hash.provider, uid: auth_hash.uid).first_or_create

  account.update_attributes(
    name: auth_hash.info.name,
    profile_image: auth_hash.info.image,
    token: auth_hash.credentials.token,
    secret: auth_hash.credentials.secret
  )

  account
end

由于您总是首先在 find_or_create_from_auth_hash 方法中创建新记录,并且您从未设置 account_namedescription,这两个都是必填字段,update_attributes 将无法通过验证,并且会静默失败。但是,您返回的是 Account 对象(未持久化),这可能会使它出现在 Account 执行 "exist" 但不在数据库中的其他方法中。