Theme:
I'm working in a rails app where I have extended a existing model called profile into two models called person and organization. I want to get organizations only when I use Organization.all and people only when I call Person.all.
Problem:
But when I use Organization.all or Person.all it returns all records without removing person form Organization.all and organization form Person.all.
What your looking for is Single Table Inheritance. You want Profile to be a base class of Person and Organisation so class Person < Profile etc.
You then want a migration to add a type field to profile
add_column :profiles, :type, :string, reference: true
Then you simply call Person.all to get all the people, and Organisation.all to get all the organisations.
https://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-1/ for reference if you have more trouble.
Related
I'm making an App in Rails to show anime, these animes has and belongs to many languages, so I made a HABTM association:
class Anime < ActiveRecord::Base
has_and_belongs_to_many :languages
end
class Language < ActiveRecord::Base
has_and_belongs_to_many :animes
end
Now I don't know how can I make associations between them, I've created many Languages' records to use them, for example, Language with ID 1 is English, Language with ID 2 is Spanish, etc... And I want to just make the associations between an anime and a language, ie, if I want to say that the Anime with ID 1 it's available in Spanish only, then in the table animes_languages I want to create the record with values anime_id: 1 and language_id: 2 and nothing more, but I belive that if I execute the command Anime.find(1).languages.create it will not use an already existing language, it will create a new language, but the only thing I want is to make associations between already existing animes with already existing languages, so, How can I do this? Should I make a model for the table animes_language?
It's confusing for me cause when I created that table as specified here enter link description here, I created the table without ID, it only have the fields anime_id and language_id.
Just to be safe I will back it up.
First you migrate your tables to remove already existing association to one or the other reference (i.e. if language already have many animes, etc).
Then you need to create a migration to create the associative table.
rails g migration CreateJoinTableAnimeLanguage anime language
Then the association pointers in your models should work properly.
class Anime < ActiveRecord::Base
has_and_belongs_to_many :languages
end
class Language < ActiveRecord::Base
has_and_belongs_to_many :animes
end
At which point whenever you want to associate one to the other already existing:
Anime.find(1).languages << Language.find(1)
Experience would recommend against trying to do this in seperate steps.
I'd say find what gets created the most, I'd guess Anime, then find a way to choose or create a language using:
class AnimeController < ApplicationController
def create
#anime = Anime.new(anime_params)
#success = #anime.save
end
private
def anime_params
params.require(:anime).permit(:stuff, :languages => [:id, :or_stuff])
end
end
Should be as simple as
anime = Anime.find(1)
language = Language.find(1)
anime.languages << language
And that will create the join record in between the two
I have a Boat Model and its Models such as Brand, Model and Year. I have also User model and I would like to connect them by adding migrations to User model of boat_id and I added belongs_to :boat and has_many :boats to User model. But I can not reach User.first.boat.name from the console even though I am able to reach Boat.first.brand.name.
When I try User.first.boat.name. Console gives an error saying;
NoMethodError: undefined method `boat' for #<User:0x0000000665dc30>
Btw: Boat Model includes model_id brand_id and year_id.
EDIT1:
Or should i remove Boat model and add model_id brand_id and year_id to User model directly.
EDIT2:
I would like to be able to reach User.first.boat.brand.name or User.first.boat.year.nameor User.first.boat.model.name
EDIT3:
Every boat has one brand, year and model. But user can have many boats
EDIT4:
What i will do is;
User can sign up and login
Then User press the link list my boat.
He/she saves the boat then the page renders to User Profile
In the User profile I do not know how to get current user boat name year etc. That is why I am confused. Sorry for the misunderstanding
I think you're confused about how Rails associations work in conjunction with how they are stored in the database. If a User can have many boats, then the foreign key needs to be on the boats table. Currently you have boat_id in the users table, this should be removed and a user_id column needs to be added to the boats table as per Matt's answer.
Reference
To achieve what you're trying to do, you'll need to setup your models in the following manner:
class User
has_many :boats
...
end
class Boat
belongs_to :user # table has a user_id column
...
end
Then you can access a boat's brand using user.boats.first.brand.name
Run rails generate migration, then fill in the change method as follows:
def change
add_column :boats, :user_id, :integer
end
Then run rake db:migrate.
You user model has_many boats, so you need the boats table to refer to users. It's probably worth reading the Rails guide for ActiveRecord associations to get a better feel for how this works: http://guides.rubyonrails.org/association_basics.html#the-has-many-association
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 trying to build a student portal in Rails 3, but I'm having some problem.
The idea is to have a users table that contains all basic data for a given person. See the UML/E-R below for example attributes.
A user can be both an Assistant and a Student at the same time.
Assistant and Student should inherit from User.
The idea was to inherit directly from the User, like this.
class User < ActiveRecord::Base
# ...
def awesome?
[true, false].sample
end
# ...
end
class Student < User
has_one :student
has_many :registered_courses, through: :students
end
Student.new.awesome?
This makes the relations in the student model very strange.
has_many :registered_courses, through: :students
I want to be able to do something like this in the end.
student.full_name
student.pin_code
student.registered_courses
One solution would be to implementing the method by hand, like this
class Student < User
has_one :student
def pin_number
student.pin_number
end
end
But it looks really strange to refer to a student object inside the student model.
Is there a clearer, better way of doing this?
Here is an example UML/E-R. I've tried to keep this example clean by removing non relevant attributes. That is why there are so few attributes in the registered course entity.
STI is not a good choice for this the way that you have articulated it here, since users can be both students and assistants. When you are using STI, you generally add a type column to specify which subclass the record really belongs to. If both Student and Assistant inherit from User, then that really isn't an option, since you'd be forced to create duplicate User records for someone who is both an Assistant and a Student.
I think you'd be better off simply having Student and Assistant rows that belong_to a Student, and then delegating the elements that are contained in User back to the User object.
I feel like Inheritance is a bad move here. If you're going to have STI like this it HAS to be one or the other.
Instead throw all your logic into the User model, all your data is there anyway. Plus since Student & Assistant aren't mutually exclusive there shouldn't be any methods that will override each other.
Why not STI?
STI is mainly meant for objects that contain the same data, but does different things with them.
For example, I have a specification that contains multiple processes(ex. build and test). So I have a order that contains processes.
process_1:
order_id: 1
specification: foo
type: build
process_2:
order_id: 1
specification: foo
type: test
In this example the only thing that changes in the data is the type, but because the type changes I know what process to perform from the specification.
I was hoping I could get feedback on major changes to how a model works in an app that is in production already.
In my case I have a model Record, that has_many PhoneNumbers.
Currently it is a typical has_many belongs_to association with a record having many PhoneNumbers.
Of course, I now have a feature of adding temporary, user generated records and these records will have PhoneNumbers too.
I 'could' just add the user_record_id to the PhoneNumber model, but wouldn't it be better for this to be a polymorphic association?
And if so, if you change how a model associates, how in the heck would I update the production database without breaking everything? >.<
Anyway, just looking for best practices in a situation like this.
Thanks!
There's two approaches that might help you with this.
One is to introduce an intermediate model which handles collections of phone numbers. This way your Record and UserRecord can both belong_to this collection model and from there phone numbers and other contact information can be associated. You end up with a relationship that looks like this:
class Record < ActiveRecord::Base
belongs_to :address_book
delegate :phone_numbers, :to => :address_book
end
class UserRecord < ActiveRecord::Base
belongs_to :address_book
delegate :phone_numbers, :to => :address_book
end
class AddressBook < ActiveRecord::Base
has_many :phone_numbers
end
This kind of re-working can be done with a migration and a bit of SQL to populate the columns in the address_books table based on what is already present in records.
The alternative is to make UserRecord an STI derived type of Record so you don't need to deal with two different tables when defining the associations.
class Record < ActiveRecord::Base
has_many :phone_numbers
end
class UserRecord < Record
end
Normally all you need to do is introduce a 'type' string column into your schema and you can use STI. If UserRecord entries are supposed to expire after a certain time, it is easy to scope their removal using something like:
UserRecord.destroy_all([ 'created_at<=?', 7.days.ago ])
Using the STI approach you will have to be careful to scope your selects so that you are retrieving only permanent or temporary records depending on what you're intending to do. As UserRecord is derived from Record you will find they get loaded as well during default loads such as:
#records = Record.find(:all)
If this causes a problem, you can always use Record as an abstract base class and make a derived PermanentRecord class to fix this:
class PermanentRecord < Record
end
Update during your migration using something like:
add_column :records, :type, :string
execute "UPDATE records SET type='PermanentRecord'"
Then you can use PermanentRecord in place of Record for all your existing code and it should not retrieve UserRecord entries inadvertently.
Maintenance page is your answer.
Generate migration which updates table structure and updates existing data. If you're against data updates in migrations - use rake task.
Disable web access (create maintenance page)
Deploy new code
Run pending migrations
Update data
Enable web access (remove maintenance page).