Reputation: 2950
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>
Upvotes: 1
Views: 258
Reputation: 13354
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.
Upvotes: 1