I'm making a Rails app with a Contact resource, with address, state, and zip fields. There's also fields for users to enter a phone number. On a form from another website that I'm using for inspiration, users can indicate whether the phone is mobile, home or office, in other words the type of phone number. I'm wondering if it's possible to create fields that accept more information about other fields on a model, or if, in this case, Phone should be a separate model (for example, Contact has_many :phones) and the type of phone number as a regular field on the Phone model.
Because in my app a User has_one Contact, I'd rather keep all the phone related information in the Contact model, rather than have User has_one Contact, and Contact has_many :phones.
Using another model is an option to achieve this. Another one is to create a Hash storing the phone numbers.
class Contact
attr_accessible :phones
serialize :phones, Hash
end
And then you could store each phone in it's appropriate key, e.g.
contact = Contact.new
contact.phones = {home: '1234-1234', work: '1234-5678', mobile: '9876-5432'}
contact.save!
And they would be accessible by the phones Hash:
contact.phone[:home] # => "1234-1234"
By providing the serialize command on the model, ActiveRecord serializes it in order to store on the database.
So it allows you to store Arrays or Hashes to the database, provided you create a text field on its table.
The migration would be:
rails g migration add_phones_to_contact phones:text
For more about serialization: api.rubyonrails.org/classes/ActiveRecord/Base.html
Related
There's a table named "Person" with attribute id as primary key and phone_number which is from user input so they are formatted in different ways. I need query the id with phone number.
For example, Person.where(:phone_number => 4155332321)
However, the number in the model could be 415-533-2321 or 4155332321. How could I write the query for that?
BTW, I can't change the phone number format in the model. Otherwise, I can convert the phone in the query and model to be the same format.
Thanks
I think you'll need a two-part approach to this.
First, you'll want to also save a "normalized" phone number to the database. This contains no formatting at all -- just numbers. This will require you to add a new column to your database, say, normalized_phone_number and write a before_save callback to store this value.
class Person
before_save :normalize_phone_number
def self.normalize_number(number)
number.gsub(/[^\d]/, '') if string.present?
end
def normalize_phone_number
self.normalized_phone_number = Person.normalize_number(self.phone_number)
end
end
Next, you'll want to write a custom class method to find the person based on a normalized number from user input. Your Person class will now include:
class Person
def self.with_normalized_phone_number(phone_number)
where(normalized_phone_number: normalize_number(phone_number)).first
end
end
You could also write Person.with_normalized_phone_number as an ActiveRecord scope, which would be my preference, but "Using a class method is the preferred way to accept arguments for scopes."
Every time I create a new company record in rails, I need to add some default (blank) contact records at that company. Front Desk, Receiving, HR, IT and so on...they won't have any data in them besides the name, just a placeholder for the user to fill in later.
So, my company model has_many contacts, and contacts belong_to company. The contact records are static and the same for every new company that gets added, but I need to pre-populate the contacts table with data, so my users don't have to.
I've read a lot about seeding the database, but I won't be able to use the terminal every time a user dynamically creates a company, and it needs to be dynamically tied to that company, the records are not agnostic. Seeding doesn't seem to be the right thing. How should this be done?
you should use a before_save filter, which checks if an attribute is empty, and otherwise set it to the default.
Using a before_save will guard against deletions later on.
But be careful only to do this for fields which will never be empty.
class Company < ActiveRecord::Base
has_many :contacts
before_save :add_defaults
def add_defaults
contacts ||= Contact.default_list # this only sets it if it's nil
# you can implement Contact#default_list as a method, or as a scope in the contacts model
end
end
What about after_create callback in Company Model?
Smth like this:
class Company < ActiveRecord::Base
has_many :contacts
after_create :add_contacts
def add_contacts
contacts.create(name: "Some name", phone: "...", ....)
end
end
Although it notionally exists for generating test data, the FactoryGirl gem is very useful for this purpose. Use it in conjunction with the after_save approach mentioned here, and you'll have a nice place to centrally define your blank records.
I'm a bit confused about STI in rails.
My situation:
I have a Contact model that has description and data string fields, to store some contact like phone, fax, email, etc.
Now when I have some specific contact type like phone number of email address I want to walidate the data format in different way and I want to make some different formating on output.
I decided to use STI as all the models have the same data with just different behaviour. And I have some questions regarding forms and CRUD operations as I don't want to go against Rails conventions.
How do I make a dropdown list in form with model type? Should I hardcode it or is there some more automated way?
How do I create a record? Should I use switch statement and according to received type create new model of according instance?
How should I update it if I'm going to change the model type? Cast the object to new class? Or create a new object and destroy the previous one?
I'll be very thankfull for your help!
Yes, should do a hardcore as there no default store for your STI models.
Generally, yes. But With Rails you could just use camelize.constantize to get class from string. Another way is just use parent model, and set type field manually. As with STI all records are in the same table and then all are of the parent class.
If you wish to update, just update type field. Then you could re-query to force Rails to get new object of different type.
You could create a model like this :
Type < ActiveRecord::Base
has_many :contacts
end
You could use this command rails g model Type name:string, add a type_id column in your contact and migrate the database.
end change your contact's model like this :
Contact < ActiveRecord::Base
belongs_to :type
end
Now, in your form, you could use this :
select("type", "type_id", Type.all.collect {|t| [ t.name, t.id ] }, { :include_blank => true })
It should resolve your problem.
Now you can do something like this :
#emails = Type.find_by_name('email').contacts
Or use scopes.
I have a simple User model which is associated to many Town objects using a join table (has_and_belongs_to_many). Now I'd like to update the towns belonging to a particular user by assigning a list of comma-separated town ids (coming directly from the form sent as a HTTP POST parameter).
The user object is saved using the following controller code:
#current_object.update_attributes(params[:user])
The params[:user] includes town_ids which is, for example, set to 1,4,6.
Unfortunately, this does not update the user-town associations at all. However, if I do it manually, it works beautifully well:
User.find(:first).town_ids = "1,4,6" # this saves automatically
Could it just be that it is not possible to mass-assign these collection_singular_ids fields?
My user model contains the following:
has_and_belongs_to_many :towns
# necessary for mass-assignment, otherwise it results in an exception:
attr_accessible :town_ids
Any help is greatly appreciated.
You have to pass the town_ids as an array:
User.find(:first).update_attributes(:town_ids=>[1,4,6])
If you pass the ids as a string Rails will attempt to convert the string to an integer:
"1,4,6".to_i # => 1
I am building an ecommerce app in rails and would like some help on my model relationships and how i get the tables populated with the information.
I have a user model, an order model and an address model. I want to capture the address in a form during the order process.
In my order model i have user_id, pay_type, email, address_id and name.
In my address I have the user_id, (then some address fields).
the relationships are
order belongs_to a user
address belongs_to a user
address belongs_to an order
order has_one address
user has_many orders
user has_one address
So when a customer clicks checkout I want them to enter the name thats on the Order, email, address and paytype. The user_id will be captured using currently signed in user method through a hidden field. (If there is a better way let me know). sorry if this isn't explained very well
You'll need to look into accepts_nested_attributes and nesting forms.
Or just look through some code here, e.g.
order model
order form
order controller
The main things here to note are:
accepts_nested_attributes_for
f.fields_for :address do |address| will be needed to render the nested form
#order.save in the controller will save all nested data