Forum: Ruby on Rails Help with many-to-many using :through

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
82ee2cbbd7a6ea331728565f766b0ff3?d=identicon&s=25 Vaishal Sheth (Guest)
on 2006-04-04 05:57
(Received via mailing list)
I am using many-to-many using :through since I need to store additional
information in the join table.

I am doing this and it seems to work. I want to verify that this is the
best
way to do this.

Tables
foods - id, food
foodallergies - food_id, symptom_id, a few other columns
symptoms - id, symptom

Models
class Food < ActiveRecord::Base
  has_many :foodallergies
  has_many :symptoms, :through => :foodallergies
end

class Symptom < ActiveRecord::Base
  has_many :foodallergies
  has_many :foods, :through => :foodallergies
end

class Foodallergy < ActiveRecord::Base
  belongs_to :foods
  belongs_to :symptoms
end

I have a JournalEntry model that stores foods and symptoms as
comma-seperated strings. Upon record creation in the JournalEntry, I
want to
parse the foods and symptoms and create a many to many relationship
between
them. I do this like this in the create method in the JournalController

  def create
    params[:journal_entry]["user_id"] = @session[:user].id
    @journal_entry = JournalEntry.new(params[:journal_entry])

    if @journal_entry.save
      # parse the foods and create a new record if food not already in
db
      params[:journal_entry]["eat"].split(%r{,\s*}).each do |food|
        f = Food.find(:first, :conditions => ["food=?", food.strip])
        unless f
          f = Food.create(:food => food)
        end

        params[:journal_entry]["symptoms"].split(%r{,\s*}).each do
|symptom|
          s = Symptom.find(:first, :conditions => ["symptom=?",
symptom.strip])
          unless s
            s = Symptom.create(:symptom => symptom)
          end
          # create join
          f.foodallergies.create(:food_id => f.id, :symptom_id => s.id)
        end
      end

      flash[:notice] = 'JournalEntry was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end

Is this the best way to do it? Since I am using create, there is a
database
interaction on every 'create'.  Is there a way to leverage ActiveRecord
functionality to batch the database interaction?

Thanks in advance,
Vaishal
0ebe4d5a7e91575265ac1a96ed49aa57?d=identicon&s=25 Sutee Dee (yoshibot)
on 2006-04-04 06:20
I can't even get :through to work.

I get this error: 'Unknown key(s): through'

Can anyone help?

Thanks!
9f0f89bbd9e1ecfbaab6584e429b7a2f?d=identicon&s=25 Josh Susser (jsusser)
on 2006-04-04 06:49
Vaishal Sheth wrote:
> I am using many-to-many using :through since I need to store additional
> information in the join table.
>
> I am doing this and it seems to work. I want to verify that this is the
> best
> way to do this.

Your has_many :through code looks solid to me. You might want to check
the association examples on my blog if you run into trouble.  I'll be
doing another one soon for working with attributes in a join model.

> Is this the best way to do it? Since I am using create, there is a database
> interaction on every 'create'.  Is there a way to leverage ActiveRecord
> functionality to batch the database interaction?

Wrap all the calls in a transaction. (JournalEntry.transaction do ...
end) When you commit the transaction all the new records will be saved
en masse. You may also be able to get some leverage by using build()
instead of create(), then when you call save on the parent object the
children objects should be saved along with. I haven't used the latter
feature with :through associations yet, so I'm not sure how well that
works. But the transaction thing should help a lot.

By the way, I suggest keeping the user_id in the session, not the user
object itself. It will save you a world of trouble trying to keep things
in sync.

--
Josh Susser
http://blog.hasmanythrough.com
82ee2cbbd7a6ea331728565f766b0ff3?d=identicon&s=25 Vaishal Sheth (Guest)
on 2006-04-04 16:34
(Received via mailing list)
Thanks Josh.  Nice example on your blog. May I suggest a tutorial on
data
entry using through with examples? A lot of people have posted examples
about how to retrieve data using :through but I couldn't find any on
data
entry issues.

Transactions..aha, I will try that out.

BTW, if instead of using create, I used the new method for foods,
symptoms
and foodallergies, would that work? Would rails then save everything in
a
batch? or would it not even allow me to do it because just using new
will
not get me an id for food or symptom and hence it wouldn't know what to
insert in the association?

Vaishal
82ee2cbbd7a6ea331728565f766b0ff3?d=identicon&s=25 Vaishal Sheth (Guest)
on 2006-04-04 16:34
(Received via mailing list)
are you are using Rails 1.1?
This topic is locked and can not be replied to.