Trung Tran
Trung Tran

Reputation: 13721

rails nested resource unknown attribute error

I have a Contract and a Task_Order model. I keep getting an unknown attribute error for contract_id Each Contract has many Task Orders. I have read other nested models unknown attribute error questions but they haven't been able to help me. Please keep in mind I am pretty new to Rails and would greatly appreciate any help I can get. I am using Rails 4.0

Contract Model:

has_many :task_orders

Contract schema:

create_table "contracts", force: true do |t|
   t.string   "contractId"
   t.string   "contractName"
 end

Task Order Model:

belongs_to :contracts

Task Order Schema:

create_table "task_orders", force: true do |t|
t.string   "contract_Id"
t.string   "task_orderId"
t.string   "task_orderName"
end

When I click Show Contract, I get the error:

unknown attribute: contract_id

This is the line that gets highlighted:

<%= form_for([@contract, @contract.task_orders.new]) do |f| %>

I can tell that Rails is trying to print out contract_id, which is not in my Contract model... so how can I get it to print out contractId instead - which is in my Contract model?

Thanks!!

Upvotes: 2

Views: 1105

Answers (3)

Richard Peck
Richard Peck

Reputation: 76774

Something you need to be aware of is the foreign_key of Rails (and relational databases in general):


Foreign Key

Rails' standard foreign_key is to use snake_case (contract_id), however, you can use non-conventional foreign_keys like this:

#app/models/order.rb
belongs_to :contract, foreign_key: "contract_Id"

#schema SHOULD be:
create_table "orders", force: true do |t|
   t.integer "contract_id" #-> should
   t.string "contract_Id" #-> your current
end

Primary Key

create_table "contracts", force: true do |t|
   t.string   "contractId" #-> don't need

   t.string   "contractName" #-> your current
   t.string "name" #-> should be
 end

Your primary_key is almost always going to be the id column. You should remove your contractId column from the contracts db!


Task Orders

You'll need to do this:

#app/models/order.rb
belongs_to :contracts
has_many :task_orders

You'll then need another model at app/models/task_order.rb


Form

Your form is showing the error. This is because you're trying to create an ActiveRecord in the view itself. You'll be much better using the standard accepts_nested_attributes_for method of passing nested model data through a form:

#app/models/contract.rb
def new
    @contract = Contract.new
    @contract.task_orders.build
end

#app/views/contracts/new.html.erb
<%= form_for @contract do |f| %>

Upvotes: 1

Pavan
Pavan

Reputation: 33542

Firstly,use singular names for belongs_to

Class TaskOrder < ActiveRecord::Base

belongs_to :contract

end

Secondly,try changing your contract_Id in your task_orders table to contract_id.

Rails by default look for model_name_id(in your case contract_id) foreign key unless if any of the custom foreign keys defined in your model.

And finally,specify the data type integer for default foreign key.In your case it should be t.integer contract_id

However if you want contract_Id as foreign key,you should define it as custom foreign key in the Contract model itself like this

Class Contract < ActiveRecord:Base

has_many :task_orders,:foreign_key => "contract_Id"

end

Upvotes: 0

cvibha
cvibha

Reputation: 713

Task Order Model should have this line belongs_to contract

belongs_to association should be declared as a singular of corresponding model

Also there should be contract_id column within task_orders table.

Diagram below explains default behavior of belongs_to in Rails

enter image description here

Upvotes: 2

Related Questions