Model:
Material
Manager
Relationship
One item needs to be approve by many managers.
One manager need to approve many items.
I do not know how to design a many_to_many relationship.
I planed to create a joined table like this
Model Approval:
item_id,
manager_id
The problem is that if I design model like this approval will have one manager or several managers, but the situation is that the number of managers could change all the time, so it is hard to set a certain number of managers in the model Approval.
How to solve this problem?
models:
class Material < ApplicationRecord
has_and_belongs_to_many :managers
end
class Manager < ApplicationRecord
has_and_belongs_to_many :materials
end
migrations:
class CreateManagerssAndMaterials < ActiveRecord::Migration
def change
create_table :managers do |t|
end
create_table :materials do |t|
end
create_table :managers_materials, id: false do |t|
t.belongs_to :manager, index: true
t.belongs_to :material, index: true
end
end
end
You can find more here
rails migrations has_and_belogs_to_many
for example in controller:
#material = Material.find(5)
#material.managers << [Manager.find(1), Manager.find(2)]
Related
Ok so what I have been doing for categories is I have had 2 tables Categories(id, name) and SubCategories(id, name, category_id) that are related through the models. I set inverse_of as you will see below.
My question is when I use to code in PHP years ago we use to have one table "Categories" and it had id, name, parent_id(0 by default) we then used that one table to control the outputs of navigations, breadcrumbs, and other navigational elements.
class CreateCategories < ActiveRecord::Migration[5.1]
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end
class CreateSubCategories < ActiveRecord::Migration[5.1]
def change
create_table :sub_categories do |t|
t.string :name
t.integer :category_id
t.timestamps
end
end
end
class Category < ApplicationRecord
has_many :sub_categories, inverse_of: :category
end
class SubCategory < ApplicationRecord
belongs_to :categories, inverse_of: :sub_category
end
I have been programming in Ruby on Rails now for over 4 years and I have yet to find a real nice "Rubyway" to achieve this. Over the years I have seen examples of using what I am already using with the 2 table method, however this does not seem very intuitive because when the system gets many categories and sub categories like 100's the page load time will be impacted in processing. Is anyone useing or know of a one table method like
class CreateCategories < ActiveRecord::Migration[5.1] def change
create_table :categories do |t|
t.string :name
t.integer :parent_id
t.timestamps
end
end
end
The problem I have always had is the model and how to get the system to realize that a record can belong to a record on the same table. I have been able to achieve it manually but I have not found a way to set it up where formtastic and other gems like rails admin would play nice with it.
Seems that you're looking for a tree structure. acts_as_tree has been around for some time. If you're using PostgreSQL, the ltree extension may be of interest as well (along with the pg_ltree gem).
I've had some experience with some self projects in Rails and I'm having some trouble creating the data model for this specific scenario. Basically, there are many users, each of whom can play many instruments, and for each user/instrument pairing, there is a certain skill level associated with it.
For example, Joe can play saxophone with skill level 5, clarinet with skill level 2, and trumpet with skill level 3. Bob can play trombone with skill level 1, saxophone with skill level 4, and clarinet with skill level 5.
I understand how to make this with traditional SQL, but I really want to be able to take advantage of the Rails ActiveRecord features (so, in theory, I could do something like this:
#users = User.all
#users.each do |user|
user.instruments do |ins|
puts ins.level #The current user's skill level on a particular instrument
end
end
How do I create the migrations/models to achieve this? Thanks!
the models are basically:
class User < ActiveRecord::Base
has_many :instrument_skills
has_many :instruments, through: :instrument_skills
end
class InstrumentSkill < ActiveRecord::Base
belongs_to :instrument
end
class Instrument < ActiveRecord::Base
end
that said you could create the models like::
rails g model User name:string
rails g model InstrumentSkill instrument_id:integer user_id:integer level:integer
rails g model Instrument name:string
then your generated migration probably look like:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps
end
end
end
class CreateInstruments < ActiveRecord::Migration
def change
create_table :instruments do |t|
t.string :name
t.timestamps
end
end
end
class CreateInstrumentSkills < ActiveRecord::Migration
def change
create_table :instrument_skills do |t|
t.integer :user_id
t.integer :instrument_id
t.integer :level
t.timestamps
end
end
end
I have 3 tables: proposals, items/proposals (items is nested inside proposals) and invoices.
I want to create invoices for those items in the proposals that got approved. How would the associations for these look like? Also, how would I set up the invoices form to choose only those items that got approved by the client?
Consider creating two different line items models for Proposal and Invoice.
class Proposal < ActiveRecord::Base
has_many :proposal_line_items
end
class ProposalLineItem < ActiveRecord::Base
belongs_to :proposal
end
class Invoice < ActiveRecord::Base
has_many :invoice_line_items
end
class InvoiceLineItem < ActiveRecord::Base
belongs_to :invoice
end
You can consider having an "approved" attribute in proposal line items. In the invoice form, you can show proposal line items approved by the client.
The suggestion of having separate line items for Proposal and Invoice is based on ERP data modeling principles to maintain the integrity of Invoice.
Update
For example here are the sample migrations for the models suggested
class CreateProposalLineItems < ActiveRecord::Migration
def change
create_table :proposal_line_items do |t|
t.references :proposal, index: true, foreign_key: true
t.string :name
t.integer :approved
t.timestamps null: false
end
end
end
class CreateProposals < ActiveRecord::Migration
def change
create_table :proposals do |t|
t.string :name
t.timestamps null: false
end
end
end
class InvoicesController < ActionController
def new
#approved_items = Proposal.find(params[:proposal_id]).proposal_line_items.where(:approved => 1)
end
end
You can iterate over the #approved_items in your view and display it to users.
V
I am in the process of building a multiclient system in ROR. (I am looking at http://guides.rubyonrails.org/association_basics.html#polymorphic-associations)
The structure is that a client has a contract, so when he logs in with his username, password and contract, he will have access to the system.
We have the contract id as a “master key”, which has to be in every table in the system.
class CreateContracts < ActiveRecord::Migration
def change
create_table :contracts do |t|
t.integer :contract_id
end
end
end
(chart of accounts)
class CreateCoas < ActiveRecord::Migration
def change
create_table :coas do |t|
t.integer :account_id
t.string :account_name
end
end
end
class CreateCustGroups < ActiveRecord::Migration
def change
create_table :custgroups do |t|
t.integer :account_id1
t.integer :account_id2
t.integer :account_id3
end
end
end
Q1: How do I define the contract with belongs_to? There has to be a relation in every table in the system to the contract table. Do I have to have a relation to all tables? (I think so)
class Contracts < ActiveRecord::Base
has_and_belongs_to_many :Coas
has_many:xxx
belongs:to
end
Q2: How do I define the association on the custgroup? Here we have a record where I have 3 or more fields that link to the same table (COA).
As Jesper said, it's quite hard to follow what you're trying to achieve, but I'll try to reply to your questions :
Q1 : If you want all your tables to reference a contract, you'll need to add to all those tables a foreign_key such as contract_id
so each create_table call will have the contract_id key
create_table :new_models do |t|
t.belongs_to :contract # this will create a contract_id field
end
you can also add an index on the column
add_index :new_models, :contract_id
then in all you models you'll add the belongs_to association :
class NewModel
...
belongs_to :contract
...
end
so if your Coas & CustGroups needs to reference the contract table, you'll have to change both migrations to include the contract_id key and then the models to add the belongs_to association
If a contract needs to have access to all Coas that references it, then you need to use the has_many association
class Contracts < ActiveRecord::Base
...
has_many :coas
...
end
It doesn't look like you need a has_and_belongs_to_many here, but i might be wrong about that.
if a contract also needs to access to CustGroups, you'll add :
has_many :cust_groups in the Contract model.
Q2 : I really didn't get understand what you want to do. Please explain what is the relation between Coas and Custgroups and I'll try to help you
Another basic Rails question:
I have a database table that needs to contain references to exactly two different records of a specific data type.
Hypothetical example: I'm making a video game database. I have a table for "Companies." I want to have exactly one developer and exactly one publisher for each "Videogame" entry.
I know that if I want to have one company, I can just do something like:
script/generate Videogame company:references
But I need to have both companies. I'd rather not use a join table, as there can only be exactly two of the given data type, and I need them to be distinct.
It seems like the answer should be pretty obvious, but I can't find it anywhere on the Internet.
Just to tidy things up a bit, in your migration you can now also do:
create_table :videogames do |t|
t.belongs_to :developer
t.belongs_to :publisher
end
And since you're calling the keys developer_id and publisher_id, the model should probably be:
belongs_to :developer, :class_name => "Company"
belongs_to :publisher, :class_name => "Company"
It's not a major problem, but I find that as the number of associations with extra arguments get added, the less clear things become, so it's best to stick to the defaults whenever possible.
I have no idea how to do this with script/generate.
The underlying idea is easier to show without using script/generate anyway. You want two fields in your videogames table/model that hold the foreign keys to the companies table/model.
I'll show you what I think the code would look like, but I haven't tested it, so I could be wrong.
Your migration file has:
create_table :videogames do |t|
# all your other fields
t.int :developer_id
t.int :publisher_id
end
Then in your model:
belongs_to :developer, class_name: "Company", foreign_key: "developer_id"
belongs_to :publisher, class_name: "Company", foreign_key: "publisher_id"
You also mention wanting the two companies to be distinct, which you could handle in a validation in the model that checks that developer_id != publisher_id.
If there are any methods or validation you want specific to a certain company type, you could sub class the company model. This employs a technique called single table inheritance. For more information check out this article: http://wiki.rubyonrails.org/rails/pages/singletableinheritance
You would then have:
#db/migrate/###_create_companies
class CreateCompanies < ActiveRecord::Migration
def self.up
create_table :companies do |t|
t.string :type # required so rails know what type of company a record is
t.timestamps
end
end
def self.down
drop_table :companies
end
end
#db/migrate/###_create_videogames
class CreateVideogames < ActiveRecord::Migration
create_table :videogames do |t|
t.belongs_to :developer
t.belongs_to :publisher
end
def self.down
drop_table :videogames
end
end
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :videogames
common validations and methods
end
#app/models/developer.rb
class Developer < Company
developer specific code
end
#app/models/publisher.rb
class Publisher < Company
publisher specific code
end
#app/models/videogame.rb
class Videogame < ActiveRecord::Base
belongs_to :developer, :publisher
end
As a result, you would have Company, Developer and Publisher models to use.
Company.find(:all)
Developer.find(:all)
Publisher.find(:all)