简体   繁体   中英

Devise + Omniauth Twitter + Twitter Gem updating attributes

I need some help. I used Devise to setup my user model. A user has many accounts . An account belongs to a user . I want to be able to update an account 's attributes with some hash values that I obtain from the Twitter API after a callback. With what I have, after the callback from Twitter, the account attributes don't get updated at all, They remain nil . How can I update an account so that it keeps the uid , token , etc after the Twitter callback. This is what I have been trying to do. 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 console shows these nil attributes after the callback.

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>

In your Account model, you have the following:

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

Since you're always creating a new record at first in your find_or_create_from_auth_hash method, and you never set account_name or description , both of which are required fields, update_attributes will fail validations, and fail silently. However, you're returning the Account object (not persisted), which could make it appear in other methods that an Account does "exist", but is not in the database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM