Specific model association case in rails - ruby-on-rails

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

Related

How to use one foreign key for two models in Ruby on Rails?

Here is my migration file
class CreateTestRevisions < ActiveRecord::Migration
def change
create_table :test_revisions do |t|
t.integer :user_id
t.integer :test_id
t.integer :question_id
t.integer :test_type
t.timestamps null: false
end
end
end
I have two models: OnlineTest & AllindiaTest.
How can I relate the t.integer :test_id to these two models?
You can set up a polymorphic association like this:
class OnlineTest < ActiveRecord::Base
has_many :test_revisions, as: :testable
end
class AllindiaTest < ActiveRecord::Base
has_many :test_revisions, as: :testable
end
class TestRevision < ActiveRecord::Base
belongs_to :testable, polymorphic: true
end
And make sure you have two columns in test_revisions table:
testable_id: integer
testable_type: string
testable_id will store id of OnlineTest or AllindiaTest.
testable_type will store OnlineTest or AllindiaTest string.
So if you have a test_devision, you can use test_devision.testable to get OnlineTest or AllindiaTest, depend on testable_type.
More information about Polymorphich assocication.
You can use foreign_key option to specify the same key for two models like:
class TestRevision < ApplicationRecord
belongs_to :online_test, foreign_key: :test_id
belongs_to :allindia_test, foreign_key: :test_id
end
Or the best way I think is to treat both of these objects as one through delegate:
delegate :allindia_test, to: :online_test
This way, you only need to have one association: online_test, and when you call, allindia_test, the call will be delegated to online_test.
Edit:
Well, if you would like to have two different relations, you would need two different ids in that case: online_test_id & all_india_test_id.
class TestRevision < ApplicationRecord
belongs_to :online_test
belongs_to :all_india_test
end

Rails: Many to many database design

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)]

Associating two models in a way both models' attributes are always pulled together in any view

I'm building a tech-specific pricegrabber-like web app, and I have a model that carries params that are common in all products. This model is called Product. Then I have one model for each type of product that I'm going to work with, for example, I'm now trying to build the first specific model, which is Videocard. So, the Product model always must have one Specific model, in this case Product-Videocard.
At this moment I'm stuck finding a way to make a product and a specific model always come tied together whenever I reach to them, be it in an index view, show view, form_for, a search, etc. But I can't picture in my head how a form will create an item and its specifications and insert a foreign key into another model with only one submit request.
Below are both models and the migrations for each:
class Product < ApplicationRecord
#belongs_to :productable, :polymorphic => true
has_one :videocard, dependent: :destroy
# Comment for this Stackoverflow question: the way I'm thinking I
# should have to make tons of has_one associations, for the other
# products. Is there a DRY way to do this?
has_many :prices, through: :stores
validates :platform, presence: { message: "should be specified." }
validates :name, presence: { message: "should be specified." }
validates_associated :videocard
end
class Videocard < ApplicationRecord
belongs_to :product
end
Migrations (shortened to make this question as clear as possible):
class CreateProducts < ActiveRecord::Migration[5.0]
def change
create_table :products do |t|
t.references :productable, polymorphic: true, index: true
t.string :name
t.string :image
t.string :partnum
t.string :manufacturer
t.string :platform #mobile, desktop, server, laptop
t.timestamps
end
end
end
class CreateVideocards < ActiveRecord::Migration[5.0]
def change
create_table :videocards do |t|
t.references :product, index: true
t.integer :memory
t.string :interface
# [...lots of attributes...]
t.integer :displayport
t.integer :minidisplayport
t.integer :tdp
t.timestamps
end
end
end
Also how can I make it so that Product only needs one has_one association, instead of using multiple ones. Remember that Videocard will have one type of specification, Memory will have other, and so on.

Render children of parent rails 4.0

I have a Contract model that has_many Task_Orders. I am trying to render a view where if I click "Show" for Contract line item, it will display a list of Task_Orders that belong to that Contract.
Here is my Contract schema:
create_table "contracts", force: true do |t|
t.string "contractId"
t.string "contractName"
Here is my Task Order schema:
create_table "task_orders", force: true do |t|
t.integer "contract_Id", limit: 255
t.string "task_orderId"
t.string "task_orderName"
Here is my Contract model:
class Contract < ActiveRecord::Base
has_many :task_orders
end
Here is my Task Order model:
class TaskOrder < ActiveRecord::Base
belongs_to :contract
end
I am not entirely sure how to work with the controller and view to make it happen.... please help. I am using Rails 4.0
Thank you.
foreign_key
Firstly, you need to ensure your foreign_keys are assigned for your associations:
#app/models/task_order.rb
Class TaskOrder < ActiveRecord::Base
belongs_to :contract, primary_key: "contractID", foreign_key: "contract_Id"
end
#app/models/contract.rb
Class Contract < ActiveRecord::Base
has_many :task_orders, primary_key: "contractID", foreign_key: "contract_Id"
end
--
Controller
This should allow you to call the required data from your controller:
#app/controllers/contracts_controller.rb
Class ContractsController < ApplicationController
def show
#contract = Contract.find params[:id]
end
end
#app/views/contracts/show.html.erb
<% for order in #contract.task_orders do %>
<%= order.id %>
<% end %>

Rails Relational Database not working how I want

In the console
a = Reported.new
This works. After tinkering.
a.profile = Profile.first
But it's not what I want! I want a.profile to even exist. I want a.reported_by to be a profile! And I want a.reported to be a profile!
Again what I want is
a.reported_by = Profile.last #or any such profile
a.reported = Profile.first #or any such profile
Model
class Profile < ActiveRecord::Base
has_many :reported, dependent: :destroy
Migration
It doesn't have a reported column, I am not sure about the right way to implement that either.
class CreateReporteds < ActiveRecord::Migration
def change
create_table :reporteds do |t|
t.belongs_to :profile
t.integer :reported_by
t.string :reason
t.timestamps
end
end
end
Your migration seems... off. I've never seen t.belongs_to :something in a migration - shouldn't it be t.integer :profile_id? (I couldn't find documentation supporting the belongs_to syntax there).
If you want Reported#reported_by to return a Profile, then you need a reported_by_id integer on it, NOT a reported_by integer. Rails has a convention where you should make your referenced objects (in this case, a belongs_to :reported_by relationship) use the relationship_id format for it's foreign key.
Then you should have this in your class:
class Reported < ActiveRecord::Base
belongs_to :reported_by, class_name: "Profile"
end
This will make it so it uses reported_by_id as the foreign key for a Profile object, but return it as Reported#reported_by.
Then:
class Profile < ActiveRecord::Base
has_many :reporteds, foreign_key: 'reported_by_id'
end
Should let you do Profile#reporteds
And your migration would look like this:
class CreateReporteds < ActiveRecord::Migration
def change
create_table :reporteds do |t|
t.integer :reported_by_id
t.string :reason
t.timestamps
end
end
end

Resources