0

Hi I am new to rails and I would like to know what is the best way who save dependent objects in an HBTM relation.

Specifically, I have two classes Post and Tag

class Post < ActiveRecord::Base
  has_and_belongs_to_many :tags
end

class Tag < ActiveRecord::Base
  has_and_belongs_to_many :posts
end

I have a migration to create the joining table

class AddPostsTagsJoinTable < ActiveRecord::Migration
  def self.up
     create_table :posts_tags, :id => false do |t|
        t.integer :post_id
        t.integer :tag_id
      end
  end

  def self.down
    drop_table :postss_tags
  end
end

All is good up to here

So I have a PostsController from which I handle the creation, updates and deletes for the posts, and I want to encapsulate the Tags so that the creation is via the PostsController... like so:

class PostsController < ApplicationController

  #... code removed for brevity

  def create
    @post  = current_user.posts.build(params[:post])
    if @post.save

      tag_names = params[:post][:tags].strip.split(' ')
      tag_names.each do |t|   

        #see if the tag already exists
        tag = Tag.find_by_name(t);
        if tag.nil?        
          @post.tags.create!(:name => t)
        else
          @post.tags << tag #just create the association
        end   

      end

      flash[:success] = "Post created."
      redirect_to(user_posts_path(current_user.username))
    else
      @user = current_user
      render 'new'
    end
  end

end

I am not sure how I should handle the creation of my Tag(s) because if I just call

@post.tags.create!(:name => t)

this will create duplicate records in the Tags table (even when :uniq => true is specified in the model).

So to avoid the duplication I see if a tag is already present and then add it like this

tag = Tag.find_by_name(t);
if tag.nil?        
  @post.tags.create!(:name => t)
else
  @post.tags << tag #just create the association
end   

Is this the way it's supposed to be done?

This seems expensive (especially 'cause it's in a loop) so I am wondering if there is another "cleaner" way to do this? (pls forget the DRY'ing up of the action and so on)

Is there a clean way to create my Tags without having to manually check for duplicates?

thank you in advance for your help!

cgiacomi
  • 4,629
  • 6
  • 27
  • 33

1 Answers1

2

You can save tags attribute of post if automatically by adding accepts_nested_attributes_for to Post model

class Post < ActiveRecord::Base
  has_and_belongs_to_many :tags
  accepts_nested_attributes_for :tags
end

The next step is to output tags fields inside post form.

Hck
  • 9,087
  • 2
  • 30
  • 25