开发者

foreign_key is always 1

开发者 https://www.devze.com 2023-02-13 20:23 出处:网络
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 enterin

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消