简体   繁体   中英

In Rails, how do you add multiple foreign keys to the same model? I have the Django equivalent

I'm using Rails 3 Beta and I assume the syntax is similar to the 2.x. I'm also not very familiar with Ruby and Rails.

In Django, multiple foreign keys to the same model looks like the following:

class Dish(models.Model):
    name = models.CharField(max_length=100)
    lunch = models.ForeignKey(Ingredient, related_name='lunch')
    dinner = models.ForeignKey(Ingredient, related_name='dinner')

class Ingredient(models.Model):
    spices = models.IntegerField()
    veggies = models.IntegerField()

In Rails, I'm thinking of doing something like the following:

# Migration file
create_table :dishes do |t|
  t.column :name, :string
end

create_table :ingredients do |t|
  t.column :spice, :integer
  t.column :veggies, :integer
  t.column: :dish_id, :integer
  t.column: :meal, :string  # lunch or dinner
end

# Models
class Dish < ActiveRecord::Base
  def lunch
    return # ingredient for the current dish where type == lunch
  end

  def dinner
    return # ingredient for the current dish where type == dinner
  end
end

Is the above the right idea or is there a better way to do it?

More Clarifications: The restaurant serves the same dish during both lunch and dinner but uses different amount of ingredient between those two meal times. Each dish can contain at most one lunch ingredient object and at most one dinner ingredient object.

Its not clear from your model if there is a 1-to-1 or 1-to-n relationship amongst Dish model and Ingredients model. If the relationship is 1-to-1 , following code should work:

class Dish < ActiveRecord::Base
 has_one :lunch, :class_name => 'Ingredient', :conditions => {:meal => 'lunch'}
 has_one :dinnner, :class_name => 'Ingredient', :conditions => {:meal => 'dinner'}

end
# now you can get lunch and dinner using the calls below on a Dish object.
dish.lunch
dish.lunch

If the relationship is 1-to-n , following code should work:

class Dish < ActiveRecord::Base
 has_many :lunches, :class_name => 'Ingredient', :conditions => {:meal => 'lunch'}
 has_many :dinnners, :class_name => 'Ingredient', :conditions => {:meal => 'dinner'}
end

Firstly for me it doesn't look good if you use string column to store only two types of something. You can store it as boolean or as integer when there are more types of meals. You can add an array that maps meal type id to lunch or dinner or anything else.

# Ingredient model
belongs_to :dish

def meal
  MEAL_TYPES[meal_id]
end

private
MEAL_TYPES = ['lunch', 'dinner']


# Dish model
has_one :lunch, :class_name => 'Ingredient', :conditions => {:meal_id => 0}
has_one :dinner, :class_name => 'Ingredient', :conditions => {:meal_id => 1}

Then in your code you can use it as fallows:

@dish = Dish.find(params[:id])
@dish.lunch # returns lunch ingredients
@dish.dinner # returns dinner ingredients

@dish.lunch.meal # => "lunch"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM