right now I use devise and have two fields. fname and lname.
I would like the ability to put a full_name field to the user model. Then the user model would take the full_name field and extract the fname and lname by splitting with a space. if there is more than one space that would all go to the fname and the last item would be the last name, and then saved to the user model with the extracted fields for fname and lname.
Is this possible without hacking up devise?
Thanks
The problem with both current answers is that they don't handle three(+) word names such as Billy Bob Thornton.
'Billy Bob Thornton'.split(/(.+) (.+)$/) => ["", "Billy Bob", "Thornton"]
'Billy Bob Thornton'.split(' ', 2) => ["Billy", "Bob Thornton"]
The original posting requests all but the last name to go to first name. So I'd suggest:
def full_name
[first_name, last_name].join(' ')
end
def full_name=(name)
elements = name.split(' ')
self.last_name = elements.delete(elements.last)
self.first_name = elements.join(" ")
end
You don't need to hack up devise persay, just do it in your Users model (or whatever modal you are usuing as your devise_for
class User
def fullname
self.fname << " " << self.lname
end
def fullname=(fname)
names = fname.split(/(.+) (.+)$/)
self.fname = names[0]
self.lname = names[1]
end
end
untested and off the top my head, but it should be a start....
i wouldn't suggest storing the fullname, just use it like a helper function, but that is up to you.
Related
I'm just starting to learn ruby on rails and using
http://ruby-for-beginners.rubymonstas.org/writing_classes/attribute_writers.html
The article doesn't explain how to display the password
Here is my code.
class Person
def initialize(name)
#name = name
end
def name
#name
end
def password=(pass)
#password = pass
end
def greet(other)
puts "Hi " + other.name
puts "Your password is " + #(how do i call password here?)
end
end
person = Person.new("Lee")
person.password = ("super secret")
person.greet(person)
p person
I'm not understanding attribute writers at this point.
Can anyone help me?
Thank you so much
While you have already set class variable #password = pass
You are able to call it as #password, remember if password wasn't set, it will give an error.
def greet(other)
puts "Hi " + other.name
puts "Your password is #{#password}"
end
person = Person.new("Lee")
person.greet(person) #will give an error
person.password = "pass"
person.greet(person) #will print the password
I'm populating a select tag dynamically within my form. The select tag is populated by a query to Payee. I have a couple fields I'd like to display as the text value of the element. However it must be done conditionally. For example.
fields:
:company
:first_name
:last_name
I can concatenate those three in the text box like so:
f.select :payee_id, Payee.all.collect { |p| [p.company.to_s + " " + p.first_name.to_s + " " + p.last_name.to_s, p.id] }
The above doesn't work the way I desire. If company exists, I would like to leave out first_name and last_name.
if company is blank, I'd like to display only first_name and last_name
currently if company and first_name exist it concatenates the two together, which I do not desire.
I know how to query the database for each case separately, but I don't know how to combine the results so the select tag will display correctly.
Here's what I have of my helper so far. I know it's currently a mess, but I need help understanding the method to get this done.
def expense_payee_id_field(f)
#payee_with_company = Payee.where("company IS NOT NULL and company !='' ")
#payee_without_company = Payee.where("(first_name != '' or last_name != '') and company = '' ")
f.select :payee_id, Payee.all.collect { |p| [p.company.to_s + " " + p.first_name.to_s + " " + p.last_name.to_s, p.id] }
end
You should just create a method in your Payee model that does this logic for you:
# Payee.rb
# I've extracted this into its own method
# because you very well may need it later
def full_name
[first_name, last_name].join(" ")
end
# This can be written more concisely, but I've
# kept it as-is to allow for better readability
def display_name
if company_name.blank?
full_name
else
company_name
end
end
Now, you can simply call payee.display_name and it will print the desired result.
#matched = [1, 2, 3]
Where each integer represents the id of an ActiveRecord object in the Inventory class. As a next step, I want to look at each of those objects and obtain the email of the parent User, but I'm not sure how to do it. Ideally I'd write something like:
Inventory.where(id: #matched).user.email
Because certainly, this statement would work if I only had a single id to look up. Since that doesn't work, I'm instead doing this
#email = []
#matched.each do |i|
#email << Inventory.find_by_id(i).user.email
end
Just wondering if there's an easier way.
Thanks!
If you only need the email addresses then you can use the pluck method:
Inventory.where(id: #matched).joins(:user).pluck("users.email")
class Inventory
def self.with_ids(ids)
sql = #matched.map{|id| "id = #{id}"}.join(" OR ")
where(sql)
end
def parent_email
user.email
end
end
Inventory.with_ids(#matched).map(&:parent_email)
I am trying pull information from a contacts table based on multiple like conditions. So far I have come up with the following
conditions = ""
conditions << "email_address LIKE '%#{params[:email_address]}%'" unless params[:email_address].blank?
conditions << " AND first_name LIKE '%#{params[:first_name]}%'" unless params[:first_name].blank?
conditions << " AND last_name LIKE '%#{params[:last_name]}%'" unless params[:last_name].blank?
conditions.sub!(/^AND/, '')
if !conditions.blank?
#contacts = Contact.where(conditions).page(params[:page]).per(10)
else
#contacts = Contact.all.page(params[:page]).per(10)
end
What I was wondering is ... is this the best way to do this? I would have thought there would be a nice way to add multiple conditions in the form of a hash and somehow specify that I want to use OR/AND and like.
I am fairly new to rails and google is not really helping much.
Thanks.
Just append the where calls directly to a scope:
#contacts = Contact.scoped
#contacts = #contacts.where("email_address LIKE '%?%'", params[:email_address]) if params[:email_address].present?
#contacts = #contacts.where("first_name LIKE '%?%'", params[:first_Name]) if params[:first_name].present?
#contacts = #contacts.where("last_name LIKE '%?%'", params[:last_name]) if params[:last_name].present?
You can use a simple loop to make it less repetative:
%(email_address first_name last_name).each do |field|
#contacts = #contacts.where("#{field} like '%?%'", params[field]) if params[field].present?
end
And do not build queries by hand by directly substituting user input into your query string. Rails makes that hard to do on purpose: You're bypassing all of Rails' sanitization and opening yourself to SQL injection.
I would have thought there would be a nice way to add multiple conditions in the form of a hash and somehow specify that I want to use OR/AND and like.
There is, but it only works with AND and =:
#contacts.where(first_name: "bob", last_name: "smith")
# select ... where first_name = 'bob' and last_name = 'smith'
I'm building a database application that tracks a lot of data for a Person, such as first_name, last_name, DOB, and 20+ more fields.
Users will need to be able to search for all of these fields. I'm having trouble writing clean code for this. The code below is what I have so far in my people_controller:
The data is submitted from a form_tag
def search
#people = Person.all
general_info_string = String.new
if(params[:first_name] != "") then general_info_string << 'people.first_name = "' + params[:first_name] + '" AND ' end
if(params[:last_name] != "") then general_info_string << "people.last_name = '" + params[:last_name] + "' AND " end
... Lots more of similar clauses
general_info_string = general_info_string[0, general_info_string.length - 5]
# ^This line removes the trailing " AND " from the string
#people = #people.where(general_info_string)
end
general_info_string is so called because there are more "where" clauses(not shown) and separate strings that I build to search for them.
The problem here is that the code looks like a mess and seems like a "hacky" way to do something that should be well supported by Rails. How could I perform this operation in a cleaner way?
That's not just hacky - it leaves you open to a string injection attack.
You need a :conditions using the ? template, like this example:
:conditions => ["key1 = ?", var]
but you need to make the template part into a string that grows once per parameter, and you need to make the var into an array that grows with each parameter's value. That gives you something like this:
template = []
values = []
if params[:first_name].present?
template.push 'people.first_name = ?'
values.push params[:first_name]
end
if params[:last_name].present?
template.push 'people.last_name = ?'
values.push params[:last_name]
end
template = template.join(' AND ')
:conditions => [template, *values]
From there, you should DRY up all those ifs, such as with a table of value keys. Then you'd loop through the table, check the key, and push its results into the arrays:
fields = [:first_name, :last_name, :shoe_size, ...]
fields.each do |field|
if params[field].present?
template.push "people.#{field} = ?"
values.push params[field]
end
end