foreign_key is always 1
I am trying to enter a foreign key value along with data collected from a form. The form data is submitting perfectly, but the foreign key is always entering as 1. I have tried several ways of entering the info, my current create method attempt is below:
def create
@product = Product.new(params[:product])
@username = User.select("company").where("email= ?", current_user.email.to_s)
@cid = User.select("id").where("company= ?", @username)
if @username != nil
@product.company_id = @cid
@product.save
end
end
Also, the find_by_something (and to_i) method throws up a No Such Method error, so I have 开发者_如何学运维used the above query syntax as a work around. If anyone can explain that as an aside...
Edit, The models: User Model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
# Setup accessible (or protected) attributes
attr_accessible :email, :password, :password_confirmation, :remember_me, :company
validates :company, :presence => true
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable
after_save :correspond
def correspond
c = Company.find_or_create_by_name(self.company)
end
end
Company Model:
class Company < ActiveRecord::Base
has_many :product, :foreign_key => 'company_id', :class_name => 'Product'
end
Product Model
class Product < ActiveRecord::Base
belongs_to :company
validates :brand, :presence => true
end
Dan's answer above is correct, but as a simpler version of it, to create the association you're describing you need:
class Company < ActiveRecord::Base
has_many :products
has_many :users
end
class Product < ActiveRecord::Base
belongs_to :company
end
class User < ActiveRecord::Base
belongs_to :company
end
The Product and User tables need a column called company_id
.
That's it! Now ActiveRecord will associate the objects intelligently on your behalf, and you can do things like:
@product = Product.new(params[:product])
@product.company = current_user.company
@product.save
The best way to understand how all these relationships work is to play with them in the console. Try things like:
Company.first.products
Company.find(2).products
Company.find_by_name('Acme').products.order('price DESC')
User.last.products.where(...)
and so on...
Lastly, a thought: You would benefit immensely from reading an introductory book on Rails. I recommend 'Beginning Rails 3'. It's a fast read, you could work through it in a weekend, and it will make the big picture of how and WHY rails works the way it works very clear to you. The time spent reading the book will QUADRUPLE your productivity and the speed at which you learn more advanced stuff, because you'll be starting with a solid foundation and approaching problems "the rails way."
Your problem today was definitely a case of "you're doing it wrong", which doesn't mean there's anything wrong with your logic, just that you're making a simple problem much more difficult by trying to reinvent the wheel unnecessarily. Learning "the rails way" will make you much more productive, and will make the whole thing a lot more fun.
Okay, after the lengthy discussion in the comments, this is what I believe you need:
# app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
# Setup accessible (or protected) attributes
attr_accessible :email, :password, :password_confirmation, :remember_me
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable
# You'll need to add a new column to your users table, called `company_id`
belongs_to :company
end
# app/models/company.rb
class Company < ActiveRecord::Base
# has_many should _always_ be a pluralised version of the class you're associating. This way, you
# don't need to explicitly specify the class/foreign_keys
has_many :products
# Also, you may as well link back to your Users
has_many :users
end
# app/models/product.rb
class Product < ActiveRecord::Base
belongs_to :company
validates :brand, :presence => true
end
# app/controllers/products_controller.rb
def create
# and now, to associate the product with the company, all you need to do is this:
@product = current_user.company.products.build(params[:product])
if @product.save
# redirect
else
# render and show errors
end
end
Rails relies heavily on convention. You really, really should follow them to make your life easier.
Instead of your manual linking of User
and Company
, I've suggested that you use a proper association.
That way, inside your Controller, all you need to do is call current_user.company
to get the company, then use the build
method on the association, and Rails will automatically handle assigning foreign keys.
Based on what you have up above... which is quite confusing, I'm going to hazard a wild guess:
You might want to try:
def create
@product = Product.new(params[:product])
@product.company = current_user.company
@product.save
...
end
The approach you were taking above shows good knowledge of SQL but also that you're not very familiar with Ruby or Rails. Let ActiveRecord make your life easy, you shouldn't ever be trying to manually set a foreign key, instead you should be building relationships using objects, as shown above.
As an aside in case you're not familiar with the convention, if you want to handle validation errors etc. in your controller you should use this where the elipsis is above:
if @product.save
redirect_to ... # Redirect to whatever the next page you want them to see is if it saves correctly.
else
render 'edit' # Otherwise show the edit view again with the errors that prevented saving
end
You're making a lot of redundant queries here. You should be able to simplify this to just the following:
def create
# so far, so good
@product = Product.new(params[:product])
# assuming that `current_user` returns an instance of User, you can replace the following two lines
# @username = User.select("company").where("email= ?", current_user.email.to_s)
# @cid = User.select("id").where("company= ?", @username)
# Rather than going back to the database twice to get an ID, you can simply grab it from `current_user`
unless current_user.company.blank?
@product.company_id = current_user.id
@product.save
end
# you should probably have an error handling / redirect / render routine here
end
That said, something about your logic seems a bit off. I would have expected company_id
to refer to the id of an instance of Company
not User
It could be that the reason your company_id
is always 1 is because the id
of the instance returned by current_user
is 1.
精彩评论