I have a table admin. In which there are two columns 'username' and 'email'. Since earlier app was in php, mistakenly the email is being used for storing username and username for emails.
Now we have migrated smaller part of application in rails, what I want is to do some changes in rails model so that username points to email and email points to username. I cannot rename column in db since it will break php side of app.
Is this possible in rails?
You can create virtual attributes to set\get username and and email fields and define getter and setter methods. Some examples can be found here:
http://railscasts.com/episodes/16-virtual-attributes?view=asciicast
UPD:
Some code
class User < ActiveRecord::Base
def username
self.email
end
def username=(name)
self.email=name
name
end
end
Related
I have an active record with a virtual attribute :email and a class method :create_with_emails. Controller calls that method with a list of emails to create records. email is not a column in the corresponding table of that active record, I need to use another model to get user_id (user_id is a column in corresponding table) from that email and then save the record to the database. However, email provided by controller may not have a user_id. In that case, API should report that to frontend. API should return all emails without user_id in an error message. Want to know what's good practice to implement a feature like this? Some sample code of the model or controller will be very helpful. Thx!
Following is a simple version of the active record I have now, but I'm not sure what's a good way to validate emails and report that back to frontend.
class MyRecord < ActiveRecord
def self.create_with_emails(emails)
email_arr = emails.split(",")
user_ids = User.where(email: email_arr).pluck(:user_id)
bulk_insert(ignore: true) do |worker|
user_ids.each do |user_id|
worker.add(user_id: user_id, another_attr: another_attr)
end
end
end
end
I am trying to make an app in Rails 4.
I am using devise and want to write an after sign up redirect path based on the following logic.
I have a user model that includes an :email attribute. I have an organisation model that includes an :email_format attribute (email attribute holds the part of the email address that comes after '#'. I have a profile model (which contains the user's information that can be altered by the user itself).
The associations are:
User - has_one: profile
Profile - belongs_to :user, belongs_to: organisation
Organisation - has_many :profiles
If the user (registering) inputs an email address that includes an email format that is saved in the db, then I want to associate that new user's profile with the organisation that has the matching email format.
Example:
New user's :email = bob#cat.com
I then check the organisation table to see if any :email_attributes stored are 'cat.com'.
If they are, then the user profile for the new user, is associated with the organisation that has the matching email_format (so the organisation_id in the relevant profile table is set to match that organisation id).
Here's my best attempt at writing this:
registrations controller:
def after_sign_up_path_for(resource)
# check if the email address the user used to register includes the email format of an organisation
if #user.email.includes? #organisation(:email_format)
# if it does match, then update the user profile so that the org id equals the org id for the org that has the matching email format
#user.profile.organisation_id.update_attribute(organisation.id == (#organisation.email includes? :email_format))
else
# set up a mandrill email sender to send this message
set_flash_message('We are just getting started and will get in touch with
you as soon as we have onboarded your organisation')
end
end
I'm new to this and don't understand how to query things well. Any pointers would be very much appreciated.
NEXT ATTEMPT
Taking the suggestion below, I've tried to add an after_create callback to my profile model as follows:
after_create :update_organisation
def update_organisation
Profile.update_attribute(organisation_id: :matching_org_id) # Associations must be defined correctly for this syntax, avoids using ID's directly.
# Profile.save
end
def matching_org_id
if #self.user.email.includes? #organisation(:email_format)
# how do you ask for the organisation with the matching email format id
profile.organisation_id: organisation.id
else
TBC
end
end
This isn't working. I'm not sure how to express this method correctly. I'm currently getting an error that says:
syntax error, unexpected '(', expecting keyword_then or ';' or '\n' if #self.user.email.includes? #organisation(:email_format)
First problem:
This part is fairly dangerous: you could have bobcat.com#gmail.com return a false positive.
if #user.email.includes? #organisation(:email_format)
Perhaps you can use store a regex format and check it via
/#cat.com$/ =~ #user.email
Try out the formats at rubular.com
Second problem:
The update method should be something similar to this.
#user.profile.update(organisation_id: #matching_organisation.id)
You will need to loop through all organisations to find the matching organisation.
Third Problem
I think this is a bad place to do this sort of manipulation. You should perhaps add an after_create hook to the user model and put these logic in that method.
I have a User model that has a "has_many" :emails association to an Email model. The user's primary email is just a column "email" for the user. However, I have this association that allows for multiple email addresses for a user.
The problem is that when a new user is created and "validates_uniqueness_of :email" is checked, it only checks other user's email column instead of possible secondary emails stored in the Email model.
I have tried to write a custom validate method in my User model that tries to find a user by the email address given and it works, but then it screws up other things in my code, like being able to add secondary email addresses or assign primary ones.
Is there a way to say something like: "validates_uniqueness_of :email through Email.all.each do {|e| errors.add :email, "this is invalid" if e.email == :email}"
This looks really sloppy, but all I'm trying to do is validate the uniqueness of the email address of a user upon creation against another model's instance's email address.
P.S. In case you are confused about the e.email, Email is the model and it has a column email that stores the email address.
You'll want to write a custom validator. Something along these lines:
class User
validates_uniqueness_of :email
validate :email_in_use
private
def email_in_use
if Email.where("lower(email) = ?", self.email.downcase).first
errors.add(:email, "There is already a user with this email")
end
end
end
I agree with #CWitty, though – you may want to consider moving the primary email address into the 'emails' table, rather than storing it straight on the User model.
It sounds like you need to think about your schema a bit. I would remove the email column from your User model and instead have all of the emails stored using the association. You could add a default flag to the Email model to signify the users default email. This would allow you to move the validates_uniqueness_of :email to the Email model and not try to check it in multiple places. Plus it cleans up your data so that it isn't in multiple places.
Suppose There is a model User with email attribute.
I have check in some of the tutorials that we can use self.email and email alone. So what is the difference in both ?
If you are in an instance method within the User model then either will work, but email on its own is an implicit scope definition - meaning that the application will look for a local email variable, then an email method/attribute. self.email explicitly skips the search for a local variable.
You can access email from different ways when you are on the User class.
self.email when you are in the User scope
a_user.email when you have specified a user
email when you are in the User class. This is valid for every method in the User class.
#email, the variable returned by the email function
attributes[:email] the ActiveRecord attribute.
All of this methods are automatically generated by the ActiveRecord model, you can see the doc for more details.
I have a user model which has multiple addresses. Now for my application in rails, address is not mandatory. So, if someone wants to create a user and enter the address after the user has been created, my application should allow that. My problem is, for Address model I have validations for Address Line 1, City and Postal Code. These fields cannot be blank. When, editing a user, the following code fails:
user.addresses << Address.new
Rails tries to create a new Address and fires an Insert command. This is going to fail because of the validations that is required in the model. The above code doesn't fail if the user is not present in the database. One solution to this problem is to create a separate form_for binding for the edit partial for user. I don't want to do that solution. Is there any solution that allows me to bind an empty Address object for an already existing User object in the database ?
Why attempt to add an empty Address object to the user.addresses collection? I think you could simply do something like:
user.addresses << Address.new unless (conditions)
I unfortunately don't know what your conditions are here, so it could be something like
user.addresses << Address.new unless params[:address].nil?
...although my guess is that you have a real Address object instead of just passing in a blank Address.new...
user.addresses << Address.new
This code isn't going to work anyway if your Address model requires its fields to be set, because you're not supplying a hash to Address.new
If you want to add the address conditionally, you probably want something like this:
if !params[:address].blank?
user.addresses.create(params[:address])
end
or
user.addresses << Address.new(params[:address]) unless params[:address].blank
If you really want to create an "empty" address object for each user (instead of just having users without addresses), you can change your validations so they only fire if the fields are filled out.
Something like this:
class Address < ActiveRecord::Base
validates_presence_of :address1, :if => :non_empty_address?
# etc
private
def non_empty_address?
!address1.blank? || !address2.blank || !city.blank? # etc
end
end
The restful_authentication plugin uses a similar approach to determine if the user's password is required.