Devise: Capitalize First Name - ruby-on-rails

I added a new field in devise called firstname, and I want it to be capitalized by devise during registration.
I first ran:
rails generate migration add_username_to_users firstname:string
then
rake db:migrate
After that I added firstname to the configure_permitted_parameters in the application_controller.rb and updated the views. I basically used this but stripped out some unnecessary stuff.
I dont know where I should put the code for capitalizing the firstname and lastname (as well as some other validating). Any guidance would be appreciated. Thanks.

I think you should put capitalization of first and last names in your User model. Every time a user is saved, you can capitalize the first and last name. In addition, all validation (or attribute pre-processing/sanitization) can be done at the model level as well.
class User < ActiveRecord::Base
before_save :capitalize_names
def capitalize_names
self.firstname = firstname.camelcase
self.lastname = lastname.camelcase
end
end

before_create
Joe Kennedy's answer is correct - you should use the before_create ActiveRecord callback
The difference here is that Devise doesn't do anything with your actual data modelling - it basically just creates a series of controllers to handle the user registration & login processes
--
If you want to ensure certain attributes of your User model are saved in a particular style, you'll be best setting it in the model itself:
#app/models/user.rb
Class User < ActiveRecord::Base
before_create :set_firstname
private
def set_firstname
self.firstname.titeize
end
end
This should allow you to set the attribute to have the first letters of each word capitalized
--
System
An alternative would be to look at your system
Why are you insisting the data be stored this way? It seems very inefficient to save all your data in the same for the sake of styling.
I would use the CSS text-transform function to do this:
#app/assets/stylesheets/application.css
.first_name { text-transform: capitalize; }
#app/views/users/show.html.erb
<%= content_tag :span, #user.firstname, class: "first_name" %>

Best Solution Ever:
class Role < ApplicationRecord
before_save :capitalize_names
def capitalize_names
self.name.titlecase
end
end
Output will be:
'super admin'.titlecase
Super Admin

This should probably go in the User Controller (or whichever controller inherits from the Devise Controller and creates the new user). In the create method, before you save the user to the database, add whatever attributes you want to it (i.e. capitalizing the first letter) and then save it.

def create
User.create(email: params[:email], first_name: params[:first_name].capitalize)
end
Although I'd suggest you just output the capitalize in your views and not when saving.

Related

Check if a table value in one model matches a table value in a different model

This question is kind of hard to ask, but basically, I have a Class model and a User model, each Class table has a token, and so does each User one. After the user submits a sign up form, how would I set the value of the users class_id in the create action? I've tried <%= f.hidden_field :app_id, :value => App.find_by_token(params[:key]) %>, but this doesn't work. Sorry for the long and confusing question, will be glad to answer more. Thanks in advance for any answers
It sounds as though you have a "relationship" where a User belongs to a Class and a Class could have many users. If that is the case then you should use rails Associations to make it easy for yourself. This would involve adding a 'has_many :users' to your Class model and a 'belongs_to :class' call to your User model. You would then just use the rails helpers to 'build' the object and save it with the association in the corresponding controllers.
The manual way to do it would be as follows from your controller:
def create
#This would involve you sending the proper class id as a hidden form field with the form field attribute named 'class_id'. You may need to add 'attr_accessor :class_id' to your User model.
if user.create(user_params)
blahblahblah
else
sorry blah blah
end
end
private
def user_params
params.require(:user).permit(:name, :email, :class_id, :etc)
end

Methods vs Attributes Rails

Was debating with a colleague of mine tonight on methods vs attributes in Rails. I swear I have seen this before unless I am crazy. Here is an example:
We have a user model and we want to be certain we have a first name and a last name prior to saving the record. I hate callbacks, but for this example, let's say it is in a before_save callback.
class User
before_save :set_first_last
def set_first_last
first_name if self.first_name.blank?
last_name if self.last_name.blank?
end
def first_name
self.first_name = self.name.split(" ").first
end
def last_name
self.last_name = self.name.split(" ").last
end
end
So, I am curious if the method "set_first_last" name is called and it sees that the attribute first_name on user is blank it will call the method "first_name", correct? The attribute first_name on user is different than a method called "first_name." So an attribute on the user object called "first_name" would be different than a method on the user class called "first_name" in Rails, correct? This would be like a class level method vs an instance method? Just want to be sure I am correct and that I am explaining this correctly.
thanks
--Mike
I think you are misreading this bit of the code:
def set_first_last
first_name if self.first_name.blank?
last_name if self.last_name.blank?
end
This code calls the first_name method, and if it is blank, calls the first_name method again (in other words the if parts of this method are pointless)
The way this code is constructed, the value of the first_name and last_name attributes will never be used (other than if you were to use them in your queries) - any time you do user.first_name it will reconstruct it from name. A more common pattern would be to have the methods that set the names called something like ensure_first_name (Basically anything that doesn't class with the getter)
Instance variables (eg #foo) are distinct from methods of the same name, although it is of course common for foo and foo= to be the methods for getting/setting an instance variable of that name. Perhaps you were thinking of that? In an event the attributes of an Activerecord model aren't stored in individual instance variables.
To answer the part I think I understand: yes, an attribute on a model is quite different than a method.
Take, for example, a User model, a Users controller, and one of its corresponding views. Let's pretend the User model itself contains first_name, last_name, and email properties:
class User < ActiveRecord::Base
#Ensure presence of the following before saving model
validates_presence_of :first_name, :last_name, :email
#Verify unique email
validates_uniqueness_of :email
#Here's our lone User method...poor guy
def admin?
self.company_members.where('? = ANY (company_members.roles)', Role::ADMIN).any?
end
end
When you get around to working with an instance of that model in your controller, it'll look something like this:
class UsersController < ApplicationController
def index
#Let's just grab a random user
#user = User.find(1)
end
end
Finally, in your view, your properties (attributes) can be accessed in the following way:
####views/users/index.html.haml####
.random-class
= "You're logged in as #{#user.first_name}!"
But we can also call User methods in the view as well. Continuing off our last example, we could add something like this:
####views/users/index.html.haml####
.random-class
= "You're logged in as #{#user.first_name}!"
- if #user.admin?
= 'Oh my gosh, our freaking User method worked!'
So in short, you're correct in that properties and methods are very different, although they look similar at times.
Lastly, it's worth pointing out that instance methods are just that: methods called on instances of a class, whereas class methods are called on an actual model object, and not a singular instance of that model object. Here's a great link to learn more about the differences.
Hope this helps!
Yes, what you explained is correct.
Your piece of coding is going to work and assign the first_name & last_name with the splitted form.
further you can write your code in this way as well (assuming your full name consists of 2 words separated by space)
#user.rb
class user
before_save :assign_individual_names
private
def assign_individual_names
first_name, last_name = name.split(' ')
end
end

how to run a one-time database change on a single user

I have Customer and each customer has_many Properties. Customers belong to a Company.
I'm trying to add a certain Property to each one of a single Company's Customers. I only want this change to happen once.
I'm thinking about using a migration but it doesn't seem right to create a migration for a change that I only ever want to happen once, and only on one of my users.
Is there a right way to do this?
You can just use rails console.
In rails c:
Company.where(conditions).last.customers.each do |customer|
customer.properties << Property.where(condition)
customer.save!
end
Validation
Depending on how you're changing the Customer model, I'd include a simple vaidation on the before_update callback to see if the attribute is populated or not:
#app/models/Customer.rb
class Customer < ActiveRecord::Base
before_update :is_valid?
private
def is_valid?
return if self.attribute.present?
end
end
This will basically check if the model has the attribute populated. If it does, it means you'll then be able to update it, else it will break
--
Strong_Params
An alternative will be to set the strong_params so that the attribute you want to remain constant will not be changed when you update / create the element:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
...
private
def strong_params
params.require(:model).permit(:only, :attributes, :to, :update)
end
end
It would be much more helpful if you explained the context as to why you need this type of functionality - that will give people the ability to create a real solution, instead of proposing ideas

Single Table Inheritance with Conditions

I have model User and model Recruiter. Currently, these are two separate tables, but I want to make them one.
Current:
User: id, username, password, name
Recruiter: id, user_id
Ideal:
User: id, username, password, role (recruiter, admin)
I understand the basics of STI. What I'm wondering is, when I perform methods on the new Recruiter controller (that inherits from User) how do I make sure all my methods are calling on users that are only a recruiter? Thus, queries along the lines of... SELECT * FROM users WHERE role = 'recruiter' for everything.
That is something rails takes care of for you, out of the box. You do not have to manually query on a particular type of user, just query on the right model.
I must also mention that by default rails assumes that your sti_column is called type, but can be overridden to role easily.
Let's admit you have your 2 classes:
class User < ActiveRecord::Base
end
class Recruiter < User
end
Rails will automagically add a type column in the users table so that in your controller, if you do something like this:
class RecruitersController < ApplicationController
def index
#recruiters = Recruiter.all
end
end
Rails will automatically fetch the records with type = 'Recruiter' and you don't even have to set this manually. If you do:
Recruiter.new(name: 'John').save
A new User will be created in database with the field type set to 'Recruiter'.
you would define your models something like this:
class User < ActiveRecord::Base
...
end
class Recruiter < User
...
def initialize
# ... special initialization for recruiters / you could put it here
super
end
...
end
and to create a new recruiter, you would do this:
Recruiter.create(:name => "John Smith")
and because of the type attribute in the STI user table (set to 'Recruiter'), the record will be for a recruiter.
You could put the special initialization for the STI models either in the model's initializer, or in a before filter with a if-cascade checking the type.
An initializer is probably much cleaner.
Have you tried has_one association?
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one

Ruby on Rails - Overriding the association id creation process

I'm trying to override the way rails apply and id to an associated object, for example:
There are 2 simple models:
class Album < ActiveRecord::Base
has_many :photos
end
class Photo < ActiveRecord::Base
belongs_to :album
end
And then I want to do this:
album = Album.new :title => 'First Album'
album.photos.build
album.save #=> true
On this case I've created a plugin that overrides the id property and replaces it to a hashed string, so what I want to do is find the methods where this album_id is being replaced for my custom method instead of the int and be able to converted before it's saved.
But I want to act globally inside Rails structure because since it will be a sort of plugin I want to make this action work on dynamic models, that's why I can't create an before_save validation on the model.
I'm not sure if it's easy to understand, but I hope someone could help me on that..
Here's a screenshot of my current table so you can see what is happening:
SQLite3 DB http://cl.ly/1j3U/content
So as you can see the album_id it's being replaced for my custom ruby object when its saved...I've disabled the plugin and then it saved normally with records 11 and 12...
I want just act on a rails action and converted with my custom methods, something like
def rails_association_replaced_method(record)
#take the record associations and apply a to_i custom method before save
super(record)
end
something like this :)
Well I hope this didn't get too complicated
Cheers
It seems if I only override theActiveRecord::Base save method do the job if handled properly
define_method 'save' do
int_fields = self.class.columns.find_all { |column| column.type == :integer }
int_fields.each do |field|
if self.attributes[field.name]
self.attributes[field.name] = self.attributes[field.name].to_i
end
end
super
end
And this shall replace all the integer fields from the Current Model applying a to_i method over the result.
Rails is unfriendly to that kind of change to the defaults. What's your end goal here?

Resources