In my rails application I have a model named "User". User has an column email and a column billing_email. When user creates account he enters the value for user.email. The column billing_email stays empty.
Inside the application I want to use "user.email" if "user.billing_email" is still empty. So unless user has enters value for his "user.billing_email", "user.email" is used.
Can someone point me in the right direction with this? And is the best place to put such code? Inside a helper or inside the user_model itself?
Override the getter in your model:
def billing_email
super.blank? ? email : super
end
But you'd rather use another method name, or keep the same name but in a decorator for instance.
I suggest you to create a new method that checks the presence of the billing_email and returns it if present, otherwise it defaults to email.
class User
def valid_email
billing_email.presence || email
end
end
you can override the billing_email
class User
def billing_email
read_attribute(:billing_email).presence || email
end
end
but I normally avoid this because it can lead to some side effects when the model gets saved or displayed.
In fact, in some cases your code may end-up storing the value of email if billing_email is blank, duplicating all the values.
It's better to go with a custom method.
Related
I have a User model that has an attribute called country. This attribute is set by a method called methodA.
Somewhere else in my code I may try to access User's country attribute and it might be blank if methodA never ran.
What I'm looking for is to run methodA if I try to access User's country attribute and it's blank.
I tried something like that in my Model :
def country
c = read_attribute(:country).presence
if c.blank?
methodA
else
return c
end
end
But I get an error when it first runs. If I reload the page, country has been set on the previous run (even tho the error) and it's all good.
I would love it to work on the first run and avoid the error page tho...
Thanks in advance for your help
You can just call super
def country
super.presence || "do whatever"
end
presence will check present? and if present? it will return its receiver; otherwise it returns a false-y value (nil).
Remember that if possible you should be setting a database default.
I have managed to achieve my goal using this :
class User < ApplicationRecord
after_find :check_country
def check_country
if country.blank?
methodA
end
end
def methodA
...code
end
end
It does work but I'm not sure if this is ideal... Because check_country will be executed everythime a User is fetched... Even if country is set.
I would prefer it to run only if country is blank.
Any idea ?
I'm currently trying to automatically create an user_address (which will be a randomly generated hash, which is for now hardcoded) string upon sign-up with the Ruby on Rails devise Gem. I have added the user_address to the list of allowed parameters I am currently trying to add this logic to the registrations_controller.rb by adding the following method :
def create
super do
current_user.user_address = '1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX'
end
end
I suppose this is because current_user must not be defined before the actual POST (create user) has been processed but I am not sure about the way to do this.
Any help would be greatly appreciated, thanks in advance
If i understand you correctly (I think I do) you could move away from trying to do this in the create action in the controller and instead use a model callback on the User model.. that way its automatically created when a user registers.
example:
class User < ApplicationRecord
before_create :assign_user_address
validates_uniqueness_of :user_address
def assign_user_address
begin
self.user_address = SecureRandom.hex
other_user = User.find_by(user_address: self.user_address)
end while other_user
end
end
the before_create will generate the user_address and assign it to the user that is registering, while the validates_uniqueness_of ensures that you will never have a duplicate user address all in one fell swoop (although with a random string the chances of duplicating are slim.. but better to be safe than sorry.. I find this method super easy and keeps your controller clean and un cluttered.
Let me know if this wasn't what you were looking for..
Have a form that has 1 field, an email address.
When submitted the model calls :before_save
Checks to see if the email address exists.
If it does, it creates a new record.
If it does not, it updates a record in another model AND NO record should be created.
Using return false to cancel the before_save for 2.2 but it rolls back the update and cancels the creation where I just want the record not to be created.
Am I on the right path? Is there a better way?
It is strange that you got user A's object, but update user B's row......
Maybe you could find the correct user object in the controller first:
#user = User.find_by_email(params[:email]) || User.new(params[:email])
User.find_by_xxx would return nil if it cannot find the corresponding object (or return the first object if there are two or more objects matched).
You could just make your own before_save method equivalent and call that instead of object.save
eg.
def custom_save
if email_address_exists? # this would be a method you create
self.save
else
# update record in other model
end
end
Then in your controller use this instead of save (ie. model.custom_save)
I have a model User and when I create one, I want to pragmatically setup some API keys and what not, specifically:
#user.apikey = Digest::MD5.hexdigest(BCrypt::Password.create("jibberish").to_s)
I want to be able to run User.create!(:email=>"something#test.com") and have it create a user with a randomly generated API key, and secret.
I currently am doing this in the controller, but when I tried to add a default user to the seeds.rb file, I am getting an SQL error (saying my apikey is null).
I tried overriding the save definition, but that seemed to cause problems when I updated the model, because it would override the values. I tried overriding the initialize definition, but that is returning a nil:NilClass and breaking things.
Is there a better way to do this?
use callbacks and ||= ( = unless object is not nil ) :)
class User < ActiveRecord::Base
before_create :add_apikey #or before_save
private
def add_apikey
self.apikey ||= Digest::MD5.hexdigest(BCrypt::Password.create(self.password).to_s)
end
end
but you should definitely take a look at devise, authlogic or clearance gems
What if, in your save definition, you check if the apikey is nil, and if so, you set it?
Have a look at ActiveRecord::Callbacks & in particular before_validation.
class User
def self.create_user_with_digest(:options = { })
self.create(:options)
self.apikey = Digest::MD5.hexdigest(BCrypt::Password.create("jibberish").to_s)
self.save
return self
end
end
Then you can call User.create_user_with_digest(:name => "bob") and you'll get a digest created automatically and assigned to the user, You probably want to generate the api key with another library than MD5 such as SHA256 you should also probably put some user enterable field, a continuously increasing number (such as the current date-time) and a salt as well.
Hope this helps
I believe this works... just put the method in your model.
def apikey=(value)
self[:apikey] = Digest::MD5.hexdigest(BCrypt::Password.create("jibberish").to_s)
end
I'm using Authlogic. I've got an Entry model and there is a validation method that I want to skip if the request was made by a logged in user (anonymous users are also allowed to create entries). I assume that UserSession.find would not be usable from inside the Entry model like it is from a controller. What is the best way to handle this situation? Do I need to write a custom save method of some sort and call it programmatically from the EntriesController? Or is there a way to check for login state from inside a model? I'm guessing that I wouldn't want to do that anyway, since the model should be in charge of object state and not application state.
Create a virtual attribute on Entry called logged_in.
attr_accessor :logged_in
In the controller, set entry.logged_in to true if the user is logged in, false if not. Then you can use that attribute in the validation method.
validate_on_create :my_check
def my_check
unless self.logged_in?
# add errors
end
end
You can use
valide_on_create :my_check, :unless => logged_in?