I'm new in Ruby. I want to create different users in ruby using iteration.
def createuser(*args)
obj = H['userClass']
obj.login = H['login']
obj.password = a.password = #default_passwd
obj.email = 'test#example.com'
obj.role = MasterUser::ROLE_MASTER_USER
end
For example I want to call this method and send these arguments:
H = Hash["userClass" => MasterUser.new, "login" => admin]
createuser(H)
What is the proper way to implement this?
Here's a modified version. It should bring you closer to your goal, while still being recognizable :
def create_user(parameters)
klass = parameters['user_class']
user = klass.new
user.login = parameters['login']
user.password = #default_passwd
user.email = 'test#example.com'
user.role = klass::ROLE_MASTER_USER
user
end
user_params = {"user_class" => MasterUser, "login" => 'admin'}
new_user = create_user(user_params)
I'd probably do something like this:
class UserFactory
attr_accessor :user
def initialize(klass)
#user = klass.new
end
def create(params = {})
user.login = params.fetch :login
user.password = params.fetch :password, 'default_password'
user.email = params.fetch :email
# user.role should just be initialised on the klass.new call, no need to do that here
# etc...
end
end
class MasterUser
ROLE = 'master_role'
attr_accessor :login, :password, :email, :role
def initialize
self.role = ROLE
end
end
which you would call like:
UserFactory.new(MasterUser).create(login: 'george', password: 'secret', email: 'me#george.com')
The reason I'd use params.fetch :login, instead of just reading it, is that in Ruby accessing a hash by a key that it doesn't have returns nil, while trying to fetch it will throw an error.
For example:
a = {}
a[:foo] #=> nil
a.fetch :foo #=> throw a KeyError
So that is a way of enforcing that the argument hash has the right keys.
Related
I have a method where an object is called but I can not seem to pull out the attributes of this object and I do not understand why.
def set_cashier
test = User.first
result = test.login
Rails.logger.debug "User is: #{result}"
as I set a breakpoint on the second line in rubymine IDE (I can see the following)
def set_cashier
test = User.first test: #<User:0x00000004809ea0>
result = test.login result: nil test: #<User:0x00000004809ea0>
Rails.logger.debug "User is: #{result}"
I know I have attributes on this object like id and login. When I run the debugger in my IDE I can see #attributes = Hash(17 elements) and I can see them listed inside as 'id' = "433" and 'login' = "firstname.lastname" etc...in the rubymine debugger it looks sort of like this...
result = nil
test = {User}#<User:0x00000004809ea0>
#attributes = Hash(17 elements)
'id' = "433"
'login' = "firstname.lastname"
...
How do I return the value of 'login'?
test = User.first seems to give an object that I can see in the debugger Variables tab that I can open and see a value for "#attributes = Hash(17 elements)" and I can see those values inside there....and yet...
"result = test.login" gives a nil result which so confusing
I would think that "test = User.first.login" should work ...
def set_cashier
test = User.first.login
result = test
Rails.logger.debug "User.first is: #{result}"
but this gives the same error ...so confusing.
(the full error displayed in the browser looks like so...)
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
I've been at this for a few days now. If this question does not make sense please let me know.
Thank you for your time.
UPDATED:
Per request of a commenter I'm including the code for the User model
(By the way...I inherited this code...so nothing in this file was written by me)
Note:
Rails 3.1 (updated from a rails 2.x app)
ruby 1.9.3p551
user.rb
class User < ActiveRecord::Base
acts_as_userstamp
has_and_belongs_to_many "roles"
# Virtual attribute for the unencrypted password
attr_accessor :password
validates_presence_of :login, :email
validates_presence_of :password, :if => :password_required?
validates_presence_of :password_confirmation, :if => :password_required?
validates_length_of :password, :within => 4..40, :if => :password_required?, :allow_nil => true
validates_confirmation_of :password, :if => :password_required?
validates_length_of :login, :within => 3..40, :allow_nil => true
validates_length_of :email, :within => 3..100, :allow_nil => true
validates_uniqueness_of :login, :email, :case_sensitive => false
validates_uniqueness_of :cashier_code, :if => :cashier_code
validates_format_of :login, :with => /[^0-9]/, :message => "must contain a non-numeric character"
before_save :encrypt_password
before_save :add_cashier_code
before_save :disable_reason_cannot_login_on_reenable
def disable_reason_cannot_login_on_reenable
return unless self.can_login && self.can_login_changed?
self.reason_cannot_login = "" if self.reason_cannot_login && self.reason_cannot_login.length > 0
end
belongs_to :contact
has_one :skedjulnator_access
####################################################
# I HAVE NO IDEA WHAT THIS IS HERE FOR, BUT IF YOU #
# FORGET ABOUT IT YOU WILL SPEND AN HOUR TRYING TO #
# FIGURE OUT WHAT YOU DID WRONG #
####################################################
# prevents a user from submitting a crafted form that bypasses activation
# anything else you want your user to change should be added here.
attr_accessible :login, :email, :password, :password_confirmation, :can_login, :shared
scope :can_login, {:conditions => ["can_login = 't'"]}
def self.hidden_columns
super + [:crypted_password, :salt]
end
def can_view_disciplinary_information?
!! (self.contact and self.contact.worker and self.contact.worker.worker_type_today and self.contact.worker.worker_type_today.name != 'inactive')
end
def update_skedjulnator_access_time
self.skedjulnator_access ||= SkedjulnatorAccess.new
self.skedjulnator_access.user_id_will_change!
self.skedjulnator_access.save!
end
def grantable_roles
self.roles.include?(Role.find_by_name('ADMIN')) ? Role.find(:all) : self.roles
end
def to_s
login
end
def self.reset_all_cashier_codes
self.find(:all).each{|x|
x.reset_cashier_code
x.save
}
end
def contact_display_name
self.contact ? self.contact.display_name : self.login
end
def add_cashier_code
reset_cashier_code if !self.shared and cashier_code.nil?
end
def reset_cashier_code
valid_codes = (1000..9999).to_a - User.find(:all).collect{|x| x.cashier_code}
my_code = valid_codes[rand(valid_codes.length)]
self.cashier_code = my_code
end
def merge_in(other)
for i in [:actions, :donations, :sales, :types, :users, :volunteer_tasks, :contacts, :gizmo_returns]
User.connection.execute("UPDATE #{i.to_s} SET created_by = #{self.id} WHERE created_by = #{other.id}")
User.connection.execute("UPDATE #{i.to_s} SET updated_by = #{self.id} WHERE updated_by = #{other.id}")
end
["donations", "sales", "volunteer_tasks", "disbursements", "recyclings", "contacts"].each{|x|
User.connection.execute("UPDATE #{x.to_s} SET cashier_created_by = #{self.id} WHERE cashier_created_by = #{other.id}")
User.connection.execute("UPDATE #{x.to_s} SET cashier_updated_by = #{self.id} WHERE cashier_updated_by = #{other.id}")
}
self.roles = (self.roles + other.roles).uniq
self.save!
end
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
def self.authenticate(login, password)
if login.to_i.to_s == login
u = find_by_contact_id(login.to_i)
else
u = find_by_login(login) # need to get the salt
end
return u if u && u.can_login && u.authenticated?(password)
return nil
end
# Encrypts some data with the salt.
def self.encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
# Encrypts the password with the user salt
def encrypt(password)
self.class.encrypt(password, salt)
end
def authenticated?(password)
crypted_password == encrypt(password)
end
def remember_token?
remember_token_expires_at && Time.now.utc < remember_token_expires_at
end
# These create and unset the fields required for remembering users between browser closes
def remember_me
remember_me_for 2.weeks
end
def remember_me_for(time)
remember_me_until time.from_now.utc
end
def remember_me_until(time)
self.remember_token_expires_at = time
self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
save(false)
end
def forget_me
self.remember_token_expires_at = nil
self.remember_token = nil
save(false)
end
# start auth junk
def User.current_user
Thread.current['user'] || User.fake_new
end
attr_accessor :fake_logged_in
def User.fake_new
u = User.new
u.fake_logged_in = true
u
end
def logged_in
! fake_logged_in
end
def to_privileges
return "logged_in" if self.logged_in
end
def privileges
#privileges ||= _privileges
end
def _privileges
olda = []
return olda if !self.can_login
a = [self, self.contact, self.contact ? self.contact.worker : nil, self.roles].flatten.select{|x| !x.nil?}.map{|x| x.to_privileges}.flatten.select{|x| !x.nil?}.map{|x| Privilege.by_name(x)}
while olda != a
a = a.select{|x| !x.restrict} if self.shared
olda = a.dup
a << olda.map{|x| x.children}.flatten
a = a.flatten.sort_by(&:name).uniq
a = a.select{|x| !x.restrict} if self.shared
end
a = a.map{|x| x.name}
a
end
def has_privileges(*privs)
positive_privs = []
negative_privs = []
privs.flatten!
for i in privs
if i.match(/^!/)
negative_privs << i.sub(/^!/, "")
else
positive_privs << i
end
end
if positive_privs.length > 0
positive_privs << "role_admin"
end
if negative_privs.length > 0
negative_privs << "role_admin"
end
my_privs = self.privileges
#puts "NEG: #{negative_privs.inspect}, POS: #{positive_privs.inspect}, MY: #{my_privs.inspect}"
return (negative_privs & my_privs).length == 0 && ((positive_privs & my_privs).length > 0 || positive_privs.length == 0)
end
# end auth junk
protected
# before filter
def encrypt_password
return if password.blank?
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
self.crypted_password = encrypt(password)
end
def password_required?
crypted_password.blank? || !password.blank?
end
end
Eliminating the IDE as source of problem:
So I ran Rails console and got the following error...
irb(main):001:0> User.first
User Load (0.5ms) SELECT "users".* FROM "users" LIMIT 1
(0.1ms) SHOW search_path
User Indexes (1.1ms) SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
WHERE i.relkind = 'i'
AND d.indisprimary = 'f'
AND t.relname = 'users'
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('"$user"','public') )
ORDER BY i.relname
User Indexes (0.4ms) SELECT c2.relname, i.indisunique, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
WHERE c.relname = 'users'
AND c.oid = i.indrelid AND i.indexrelid = c2.oid
AND i.indisprimary = 'f'
AND i.indexprs IS NOT NULL
ORDER BY 1
(Object doesn't support #inspect)
=>
irb(main):002:0>
...very confusing
I've got TWO apps...an old Rails 2.3.14 app and the same code updated to Rails 3.1.0. (I know 6.x is recent but I'm taking small steps first)
I'm testing both apps against the same postgres database in turns
When I run the 2.3 app in console and pull up Rails console I get a result...
>> User.first
=> #<User id: 433, login: "danny.vally", email: "danny.vally#gmail.com", crypted_password: "xxxxxxxxxxxxxxxxxxxxxxx", salt: "yyyyyyyyyyyyyyyyyyyyyyyy", created_at: "2015-12-11 10:56:17", updated_at: "2016-10-01 00:00:23", remember_token: nil, remember_token_expires_at: nil, contact_id: 1222222, created_by: 333, updated_by: 434, cashier_code: 9555, can_login: false, last_logged_in: "2016-03-05", shared: false, reason_cannot_login: "Account disabled due to 280 days of inactivity.">
Great...I can see the DB and see a user in the User model.
Now, on the Rails 3.1.0 version (pointing to the same DB...after exiting the other app)....I get the following in rails console...
$ rails c
/home/fonso/.rbenv/versions/1.9.3-p551/lib/ruby/gems/1.9.1/gems/soap4r-ruby1.9-2.0.5/lib/xsd/iconvcharset.rb:9:in `<top (required)>': iconv will be deprecated in the future, use String#encode instead.
/home/fonso/.rbenv/versions/1.9.3-p551/lib/ruby/gems/1.9.1/gems/12_hour_time-0.0.4/lib/12_hour_time/action_view_helpers.rb:3: warning: already initialized constant POSITION
Loading development environment (Rails 3.1.0)
irb(main):001:0> User.first
User Load (0.7ms) SELECT "users".* FROM "users" LIMIT 1
(0.1ms) SHOW search_path
User Indexes (1.1ms) SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
WHERE i.relkind = 'i'
AND d.indisprimary = 'f'
AND t.relname = 'users'
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('"$user"','public') )
ORDER BY i.relname
User Indexes (0.4ms) SELECT c2.relname, i.indisunique, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
WHERE c.relname = 'users'
AND c.oid = i.indrelid AND i.indexrelid = c2.oid
AND i.indisprimary = 'f'
AND i.indexprs IS NOT NULL
ORDER BY 1
(Object doesn't support #inspect)
=>
irb(main):002:0>
Here is the User model is that helps ...
class User < ActiveRecord::Base
Rails.logger.debug "User Model called"
acts_as_userstamp
has_and_belongs_to_many :roles
# Virtual attribute for the unencrypted password
attr_accessor :password
validates_presence_of :login, :email
validates_presence_of :password, :if => :password_required?
validates_presence_of :password_confirmation, :if => :password_required?
validates_length_of :password, :within => 4..40, :if => :password_required?, :allow_nil => true
validates_confirmation_of :password, :if => :password_required?
validates_length_of :login, :within => 3..40, :allow_nil => true
validates_length_of :email, :within => 3..100, :allow_nil => true
validates_uniqueness_of :login, :email, :case_sensitive => false
validates_uniqueness_of :cashier_code, :if => :cashier_code
validates_format_of :login, :with => /[^0-9]/, :message => "must contain a non-numeric character"
before_save :encrypt_password
before_save :add_cashier_code
before_save :disable_reason_cannot_login_on_reenable
def disable_reason_cannot_login_on_reenable
return unless self.can_login && self.can_login_changed?
self.reason_cannot_login = "" if self.reason_cannot_login && self.reason_cannot_login.length > 0
end
belongs_to :contact
has_one :skedjulnator_access
# attr_accessible :login, :email, :password, :password_confirmation, :can_login, :shared
# S.O. says this line will not work for Rails 3.1
# https://stackoverflow.com/questions/68291144/can-not-seem-to-pull-out-the-attributes-of-this-object
scope :can_login, {:conditions => ["can_login = 't'"]}
def self.hidden_columns
super + [:crypted_password, :salt]
end
def can_view_disciplinary_information?
!! (self.contact and self.contact.worker and self.contact.worker.worker_type_today and self.contact.worker.worker_type_today.name != 'inactive')
end
def update_skedjulnator_access_time
self.skedjulnator_access ||= SkedjulnatorAccess.new
self.skedjulnator_access.user_id_will_change!
self.skedjulnator_access.save!
end
def grantable_roles
self.roles.include?(Role.find_by_name('ADMIN')) ? Role.find(:all) : self.roles
end
def self.reset_all_cashier_codes
self.find(:all).each{|x|
x.reset_cashier_code
x.save
}
end
def contact_display_name
self.contact ? self.contact.display_name : self.login
end
def add_cashier_code
reset_cashier_code if !self.shared and cashier_code.nil?
end
def reset_cashier_code
valid_codes = (1000..9999).to_a - User.find(:all).collect{|x| x.cashier_code}
my_code = valid_codes[rand(valid_codes.length)]
self.cashier_code = my_code
end
def merge_in(other)
for i in [:actions, :donations, :sales, :types, :users, :volunteer_tasks, :contacts, :gizmo_returns]
User.connection.execute("UPDATE #{i.to_s} SET created_by = #{self.id} WHERE created_by = #{other.id}")
User.connection.execute("UPDATE #{i.to_s} SET updated_by = #{self.id} WHERE updated_by = #{other.id}")
end
["donations", "sales", "volunteer_tasks", "disbursements", "recyclings", "contacts"].each{|x|
User.connection.execute("UPDATE #{x.to_s} SET cashier_created_by = #{self.id} WHERE cashier_created_by = #{other.id}")
User.connection.execute("UPDATE #{x.to_s} SET cashier_updated_by = #{self.id} WHERE cashier_updated_by = #{other.id}")
}
self.roles = (self.roles + other.roles).uniq
self.save!
end
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
def self.authenticate(login, password)
if login.to_i.to_s == login
u = find_by_contact_id(login.to_i)
else
u = find_by_login(login) # need to get the salt
end
return u if u && u.can_login && u.authenticated?(password)
return nil
end
# Encrypts some data with the salt.
def self.encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
# Encrypts the password with the user salt
def encrypt(password)
self.class.encrypt(password, salt)
end
def authenticated?(password)
crypted_password == encrypt(password)
end
def remember_token?
remember_token_expires_at && Time.now.utc < remember_token_expires_at
end
# These create and unset the fields required for remembering users between browser closes
def remember_me
remember_me_for 2.weeks
end
def remember_me_for(time)
remember_me_until time.from_now.utc
end
def remember_me_until(time)
self.remember_token_expires_at = time
self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
save(false)
end
def forget_me
self.remember_token_expires_at = nil
self.remember_token = nil
save(false)
end
# start auth junk
def User.current_user
Thread.current['user'] || User.fake_new
end
attr_accessor :fake_logged_in
def User.fake_new
u = User.new
u.fake_logged_in = true
u
end
def logged_in
! fake_logged_in
end
def to_privileges
return "logged_in" if self.logged_in
end
def privileges
#privileges ||= _privileges
end
def _privileges
olda = []
return olda if !self.can_login
a = [self, self.contact, self.contact ? self.contact.worker : nil, self.roles].flatten.select{|x| !x.nil?}.map{|x| x.to_privileges}.flatten.select{|x| !x.nil?}.map{|x| Privilege.by_name(x)}
while olda != a
a = a.select{|x| !x.restrict} if self.shared
olda = a.dup
a << olda.map{|x| x.children}.flatten
a = a.flatten.sort_by(&:name).uniq
a = a.select{|x| !x.restrict} if self.shared
end
a = a.map{|x| x.name}
a
end
def has_privileges(*privs)
positive_privs = []
negative_privs = []
privs.flatten!
for i in privs
if i.match(/^!/)
negative_privs << i.sub(/^!/, "")
else
positive_privs << i
end
end
if positive_privs.length > 0
positive_privs << "role_admin"
end
if negative_privs.length > 0
negative_privs << "role_admin"
end
my_privs = self.privileges
#puts "NEG: #{negative_privs.inspect}, POS: #{positive_privs.inspect}, MY: #{my_privs.inspect}"
return (negative_privs & my_privs).length == 0 && ((positive_privs & my_privs).length > 0 || positive_privs.length == 0)
end
# end auth junk
protected
# before filter
def encrypt_password
return if password.blank?
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
self.crypted_password = encrypt(password)
end
def password_required?
crypted_password.blank? || !password.blank?
end
end
I've been pouring over this for weeks but I'm stumped. Is there any hope? Is this some sort of glitch in 3.1.0 that might have been fixed in some later version? Maybe 3.1.1? Or is it impossible to upgrade from 2.3.14 to 3.1.0?
Thank you for your time.
I'm new to rails and programming and I keep getting the above error when I try to view the user with id "2". I'm using the twitter-omniauth and twitter gems to view a users tweets. I have no clue whats wrong, any help would be really appreciated.
class UsersController < ApplicationController
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(params[:id])
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
def indexed
#providers = Providers.for(#user)
end
These are my models.
user.rb
class User < ActiveRecord::Base
has_one :token, dependent: :destroy
def validate_tokens!
tokens.each(&:validate_token!)
end
feed.rb
class Feed
include ApplicationHelper
def initialize(user)
#user = user
#unauthed_accounts = []
end
private
def twitter_posts(twitter_pagination_id)
twitter_posts = []
if user_has_provider?('twitter', #user)
twitter_timeline = Twitter::Timeline.new(user)
begin
twitter_posts = twitter_timeline.posts(twitter_pagination_id).map { |post| Twitter::Post.from(post) }
#twitter_pagination_id = twitter_timeline.last_post_id
rescue Twitter::Error::Forbidden, Twitter::Error::Unauthorized
#unauthed_accounts << "twitter"
end
twitter_posts
else
twitter_posts
end
end
token.rb
class Token < ActiveRecord::Base
validates :provider, presence: true
validates :uid, presence: true
belongs_to :user
def self.by_name(name)
where(provider: name)
end
def self.update_or_create_with_twitter_omniauth(id, auth)
token = where(provider: auth["provider"], uid: auth["uid"]).first_or_initialize
token.provider = auth["provider"]
token.uid = auth["uid"]
token.access_token = auth["extra"]["access_token"].token
token.access_token_secret = auth["extra"]["access_token"].secret
token.user_id = id
token.save!
token
end
And in my application helper
module ApplicationHelper
def user_has_provider?(provider, user)
#user.token.by_name(provider).any?
end
end
Error:
app/helpers/application_helper.rb:14:in `user_has_provider?'
app/models/feed.rb:27:in `twitter_posts'
app/models/feed.rb:18:in `posts'
app/controllers/users_controller.rb:62:in `feed'
Issue is on line: feed = Feed.new(params[:id])
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(params[:id]) # HERE AT THIS LINE!!
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
It should be:
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(#user) # Should be #user!!
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
Because, Feed's constructor expects a user object and you're passing params[:id] which is "2" and hence the error: undefined method `tokens' for “2”:String.
This is what I have in the user.rb...
def apply_omniauth(auth)
#abort(auth.inspect)
# name, :avatar, :tagline, :bio, :phone, :website, :city, :background, :bioextended, :username
# In previous omniauth, 'user_info' was used in place of 'raw_info'
self.email = auth['extra']['raw_info']['email']
self.name = auth['extra']['raw_info']['name'] if auth['extra']['raw_info']['name'].present?
self.city = auth['extra']['raw_info']['location']['name'] if auth['extra']['raw_info']['location'].present?
self.website = auth['extra']['raw_info']['website'] if auth['extra']['raw_info']['website'].present?
#self.username = auth['extra']['raw_info']['username'].parameterize if auth['extra']['raw_info']['username'].present?
self.username = self.id
if auth['info']['image'].present?
url = "#{auth['info']['image']}?type=large" #.sub!('square', 'large')
self.get_avatar(url)
end
# Again, saving token is optional. If you haven't created the column in authentications table, this will fail
authentications.build(:provider => auth['provider'], :uid => auth['uid'], :token => auth['credentials']['token'])
end
def get_avatar(url)
extname = File.extname(url)
basename = File.basename(url, extname)
file = Tempfile.new([basename, extname])
file.binmode
open(URI.parse(url)) do |data|
file.write data.read
end
file.rewind
self.avatar = file
end
And this is my scope...
the_scope = 'email, read_stream, read_friendlists, friends_likes, friends_status, offline_access'
It collects the name, email, avatar, and city. But, when I try to get it to collect extra properties such as website and user likes it doesn't retrieve them.
Any ideas on how to retrieve those two properties?
I wrote a form object to populate an Order, Billing, and Shipping Address objects. The populate method looks pretty verbose. Since the form fields don't correspond to Address attributes directly, I'm forced to manually assign them. For example:
shipping_address.name = params[:shipping_name]
billing_address.name = params[:billing_name]
Here's the object. Note that I snipped most address fields and validations, and some other code, for brevity. But this should give you an idea. Take note of the populate method:
class OrderForm
attr_accessor :params
delegate :email, :bill_to_shipping_address, to: :order
delegate :name, :street, to: :shipping_address, prefix: :shipping
delegate :name, :street, to: :billing_address, prefix: :billing
validates :shipping_name, presence: true
validates :billing_name, presence: true, unless: -> { bill_to_shipping_address }
def initialize(item, params = nil, customer = nil)
#item, #params, #customer = item, params, customer
end
def submit
populate
# snip
end
def order
#order ||= #item.build_order do |order|
order.customer = #customer if #customer
end
end
def shipping_address
#shipping_address ||= order.build_shipping_address
end
def billing_address
#billing_address ||= order.build_billing_address
end
def populate
order.email = params[:email]
shipping_address.name = params[:shipping_name]
shipping_address.street = params[:shipping_street]
# Repeat for city, state, post, code, etc...
if order.bill_to_shipping_address?
billing_address.name = params[:shipping_name]
billing_address.street = params[:shipping_street]
# Repeat for city, state, post, code, etc...
else
billing_address.name = params[:billing_name]
billing_address.street = params[:billing_street]
# Repeat for city, state, post, code, etc...
end
end
end
Here's the controller code:
def new
#order_form = OrderForm.new(#item)
end
def create
#order_form = OrderForm.new(#item, params[:order], current_user)
if #order_form.submit
# handle payment
else
render 'new'
end
end
Noe I am not interested in accepts_nested_attributes_for, which presents several problems, hence why I wrote the form object.
def populate
order.email = params[:email]
shipping_params = %i[shipping_name shipping_street]
billing_params = order.bill_to_shipping_address? ?
shipping_params : %i[billing_name billing_street]
[[shipping_address, shipping_params], [billing_address, billing_params]]
.each{|a, p|
a.name, a.street = params.at(*p)
}
end
How about
class Order < ActiveRecord::Base
has_one :shipping_address, class_name: 'Address'
has_one :billing_address, class_name: 'Address'
accepts_nested_attributes_for :shipping_address, :billing_address
before_save :clone_shipping_address_into_billing_address, if: [check if billing address is blank]
Then when you set up the form, you can have fields_for the two Address objects, and side step the populate method entirely.
A possible fix would be to use a variable for retrieving those matching params, like so:
def populate
order.email = params[:email]
shipping_address.name = params[:shipping_name]
shipping_address.street = params[:shipping_street]
# etc...
#set a default state
shipping_or_billing = "shipping_"
#or use a ternary here...
shipping_or_billing = "billing_" if order.bill_to_shipping_address?
billing_address.name = params["shipping_or_billing" + "name"]
billing_address.street = params["shipping_or_billing" + "street"]
...
end
Your address classes should probably have a method that would set the values for all the address properties from a hash that it would receive as an argument.
That way your populate method would only check for order.bill_to_shipping_address? and them pass the correct dictionary to the method I'm suggesting.
That method on the other hand, would just assign the values from the hash to the correct properties, without the need for a conditional check.