I'm wondering how many to many relationships are specified for phoenix.gen.html or phoenix.gen.json while scaffolding the app. It's common to use references to create one-to-many relationships, like below:
mix phoenix.gen.model Video videos name:string approved_at:datetime description:text likes:integer views:integer user_id:references:users
But how to pass many-to-many fields?
Run
mix phoenix.gen.model UserVideo users_videos user_id:references:users video_id:references:videos
and then update your schemas
alias MyApp.{User, UserVideo}
schema "videos" do
...
many_to_many :users, User, join_through: UserVideo
end
alias MyApp.{Video, UserVideo}
schema "users" do
...
many_to_many :videos, Video, join_through: UserVideo
end
Related
I have 3 models Company, Officer, Documents the data for them is extracted from a Api with Httparty one at the time. Every model has a company_number attribute(type :string some of them start with 0 or letters) that is the same in all models. Is it possible to add association based on the company_number?
i want to be able to do company.officers and company.documents as per Company has_many :officers has_many :documents respectiv belongs_to :company
thank you
thank you, I resolved the problem by renaming the columns company_number in officer and documents models to company_id and added htm association in models
I have a case where one model is related 2 other ones. I am trying to correctly setup the model relationships between these 3 models.
A simplified example... The first 2 tables are clients and invoices:
db.create_table(:clients) do
primary_key :id
String :name
end
db.create_table(:invoices) do
primary_key :id
String :description
Integer :balance
end
A third table, called files, contains records for files which can be related to either clients or invoices:
db.create_table(:files) do
primary_key :id
String :name
String :path
String :type # [image, pdf, word, excel]
end
There are 2 joiner tables to connect files to clients and invoices:
db.create_table(:clients_files) do
Integer :client_id
Integer :file_id
end
db.create_table(:files_invoices) do
Integer :invoice_id
Integer :file_id
end
The question is, how to correctly set up the relationships in the models, such that each client and invoice can have one or more related files?
I can accomplish this using many_to_many and has_many :through associations, however, this doesn't seem to be the right approach, because a given file can belong to only one customer or invoice, not to many.
I can also do this using polymorphism, but the documentation discourages this approach:
Sequel discourages the use of polymorphic associations, which is the
reason they are not supported by default. All polymorphic associations
can be made non-polymorphic by using additional tables and/or columns
instead of having a column containing the associated class name as a
string.
Polymorphic associations break referential integrity and are
significantly more complex than non-polymorphic associations, so their
use is not recommended unless you are stuck with an existing design
that uses them.
The more correct association would be one_to_many_through or many_to_one_through, but I can't find the right way to do this. Is there a vanilla Sequel way to achieve this, or is there a model plugin that provides this functionality?
With your current schema, you just want to use a many_to_many association to files:
Client.many_to_many :files
Invoice.many_to_many :files
To make sure each file can only have a single client/invoice, you can make file_id the primary key of clients_files and files_invoices (a plain unique constraint/index would also work). Then you can use one_through_one:
File.one_through_one :client
File.one_through_one :invoice
Note that this still allows a File to be associated to both a client and an invoice. If you want to prevent that, you need to change your schema. You could move the client_id and invoice_id foreign keys to the files table (or use a single join table with both keys), and have a check constraint that checks that only one of them is set.
Note that the main reason to avoid polymorphic keys (in addition to complexity), is that it allows the database to enforce referential integrity. With your current join tables, you aren't creating foreign keys, just integer fields, so you aren't enforcing referential integrity.
I have an existing legacy Firebird database with nonstandard table and field names.
I would like to write a Sinatra app that can access it and display information. I've seen stuff like dm-is-reflective that appears to work when a database has proper naming conventions, but how do I use DataMapper (or ActiveRecord whichever is the easiest) to access those tables?
For example, assuming I had these two tables:
Bookshelfs
shelf_id: integer
level: integer
created: timestamp
Book
id: integer
id_of_shelf: integer
title: string
pages: integer
Something like with odd naming conventions that don't follow any set pattern and where one table's record might "own" multiple entries in another table even though there is not foreign_key assigned.
How would you set up datamapper (or activerecord) to communicate with it?
Look in to this gem to get setup with ActiveRecord on Sinatra:
https://github.com/bmizerany/sinatra-activerecord
As for how to define the relations, activerecord can do this easily.
class Book < ActiveRecord::Base
belongs_to :bookshelf, :class_name => 'Bookshelf', :foreign_key => 'id_of_shelf'
end
class Bookshelf < ActiveRecord::Base
has_many :books, :class_name => 'Book', :foreign_key => 'id_of_shelf'
end
Assuming you figured out how to connect to your legacy database using ActiveRecord's Firebird adapter, the next thing I would do is define a view on top of each table, e.g.
CREATE VIEW books AS SELECT * FROM Book;
CREATE VIEW bookshelves AS SELECT * FROM Bookshelfs;
This way you can simply define models Book and Bookshelf in ActiveRecord as per usual and it will find everything in the right place inside the database.
I'm looking for a suggestion on how to set up two models, Teacher and Subject. A Teacher can have many Subjects, and a Subject can have many Teachers. Another thing to consider in the relationship between the two models is that a Teacher can create a Subject and add other Teachers to the Subject.
I think I'm solid on the basics of the set up for each model:
for teacher.rb:
has_many :subjects
for subject.rb:
has_many :teachers
and the teachers table should have a subject_id column and the subject table should have a teacher_id column.
What I'm not sure about is how to set up the views (and corresponding controller methods) to allow the addition of a Teacher to a Subject.
Any suggestions (or links to examples) are greatly appreciated. I haven't been able to find anything on this exact case.
current set up:
standard CRUD for a Student object
standard CRUD for a Project object
I'm likely missing something simple in how to tie these models together (other than the part of changing has_many to habtm) and getting records into the subjects_teachers table, and I still can't find a good example...
You need to build the relational table between them. It's impossible to have a many-many relationship without a rel table
First off though, it's a has_and_belongs_to_many :subjects and has_and_belongs_to_many :teachers (commonly referred to as habtm)
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
run
rails g migration subjects_teachers
open up the migration:
create_table :subjects_teachers, :id => false do |t| # ID => FALSE = IMPORTANT
t.references :subject
t.references :teacher
# NO TIMESTAMPS
end
run
rake db:migrate and you should be set!
then
see these railscasts for setting up your controllers
http://railscasts.com/episodes/17-habtm-checkboxes
http://railscasts.com/episodes/47-two-many-to-many
I have two tables, users and groups. A user can belong to many groups. A group can have many users.
So I have created a have_and_belongs_to_many relationship between users and groups using a join table, groups_users. This all works as expected.
What I would also like to do is specify an ACTIVE group for each user. Were it not for the habtm relationship I have already defined, I would create a column “group_id” in users for the active group, and then I would define a one-to-many relationship between the models as follows:
class User < ActiveRecord::Base
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :users
end
This didn’t work. I could not access group properties like “#user.group.name”. I suspect that I’m asking too much of Rails by specifying two relationships.
So I have three questions.
I could very easily understand if combining the two relationships confuses Active Record . Is that the case?
If so, how would you implement these relationships? Right now I’m just manually using the group_id, but that feels messy.
Regardless of whether I am using Active Record magic or manually setting the active group, it is possible for a user’s active group to be outside the group’s they belong to using the first habtm relationship. Any thoughts on how to implement this with the constraint that the active group must be a group that the user belongs to?
Thanks for any insights. I am a couple of weeks into the Rails learning curve and I think that getting to the bottom of this little problem will deepen my understanding of models and table relationships quite a bit.
Greg - I've done this before, similar to what as your proposing. I used a "primary_group" instead of "group" and set the foreign_key to be "primary_group_id" and the :class_name => 'Group'
I don't use has_and_belongs_to_many very often so I don't know if that would be causing an issue, but I don't think so - at least not with the user model. You don't have a #group method, so setting belongs_to should be OK. I don't know if you absolutely must have have a has_many :users method on the group, but you may not need it anyway. This will certainly cause a collision with the 'users' method that habtm creates. If you do need this, try has_many :primary_users and set the :foreign_key => :primary_group_id
Just some thoughts. You should be able to do what you're doing now, so not sure what's failing.