views:

324

answers:

4

Hi

I currently have 3 tables.

snippet tags snippet_tags

I'm using HABTM.

So I did a form to save a snippet with tags. Keywords are in a text field, separated by commas.

What I need to do is to take the string from this text field, loop on the keywords, check if they exist, if not create them, and THEN save the snippet.

I tried with a before_save but it doesn't seem to go by that way..

So if you could help me, it'd great!

Thanks a lot!

A: 

Try before_update?

Jim
`before_save` is a combination of `before_save` and `before_create` so I don't think this will help.
samg
+1  A: 
  1. Use split to break your string into an array of the tags
  2. Find each tag by name
  3. If not found then create the tag
  4. Add the tag to the snippet
  5. Save the snippet (in your controller)

Example method to put in your snippet model

def add_tags(tag_list_string)
   tag_array = tag_list_string.split ','
   tag_array.each do |tag_name|
     tag = (Tag.find_by_name(tag_name) || Tag.create(:name => tag_name))
     self.tags << tag
   end
end
JosephL
I know for the method, how to do it and all.But what I don't know is what to do, like in my controller...I'd like to know how to save that snippet. Because it tells meActiveRecord::AssociationTypeMismatch (Tag(#2180942420) expected, got String(#2148246520)):
Tom
Can you post your controller save method and your add_tags method from your snippet model? Then I can see what is going on.
JosephL
+1  A: 

I think JosephL's answer is pretty good. Although, I would do it all in the snippets_controller action:

def create
  @snippet = Snippet.new(params[:snippet])

  @snippet.tags = params[:tags].split(',').collect { |tag| Tag.find_or_create_by_name(tag) }

  if @snippet.save
    # do something when successful
  else
    # do something when saving failed
  end
end

Sorry for that long, one-line statement. ;-)

I didn't test the code, but I hope it works.
Tag.find_or_create_by_name will do exactly that: when a tag with that name exists, it will return it, otherwise it will create the new tag on the fly and return that.
This way, the tags are already saved, before you call @snippet.save.

Please note, that I just assumed, how your variables and parameters are named.

Daniel Pietzsch
LOL Here's my controller:http://pastie.org/705756I'll try your way :) I didn't know that there was a find_or_create method!But the problem is: whenever I do Snippet.new(params[:snippet]) it tells me: ActiveRecord::AssociationTypeMismatch (Tag(#2181591060) expected, got String(#2148246520)): app/controllers/snippet_controller.rb:18:in `new' app/controllers/snippet_controller.rb:18:in `create'Thanks for your help!
Tom
Even with your way it doesn't work your way too. But the idea is great and I think I must have some kind of problem with my models... I dunno.http://pastie.org/705758
Tom
I suspect, you might have a name conflict. If `params[:snippet]` include the `:tags` key, Rails will try to assign you tags string using the `tags` method you gained from them HABTM association. Please check, if the input fields in the form you send, do not have a name and id like `snippet[tags]` and `snippet_tags` respectively.If this is the case, try not to use something like `f.text_field :tags`. Use the `text_field_tag` method to pass your comma-delimited tags.But I am guessing here. It would help, if you could post the code from your view or the parameter list from your log file.
Daniel Pietzsch
Great! what you said worked as expected!But now I get this:Primary key is not allowed in a has_and_belongs_to_many join table (snippets_tags).Thanks!
Tom
+1  A: 

Here is a version of your create method. The main change is not creating a Snippet_Tag. If your HABTM association is set up correctly then your snippet will have a tags collection which you can add your tags to. The collection will be persisted as Snippet_Tags by ActiveRecord. See the rails associations guide for more details on HABTM associations.

def create
  # Creating the snippet
  @snippet = Snippet.new
  @snippet.title = params[:snippet][:title]
  @snippet.content = params[:snippet][:content]

  # loop through the tags
  params[:snippet][:tags].split(',').collect do |tag_string|
    tag_string.strip!
    if tag_string.length > 0
      # Find or create tag
      tag = Tag.find_or_create_by_name(tag_string)

      # Add tag to tags collection
      @snippet.tags << tag
    end
  end

  if @snippet.save
    # do something when successful
  else
    # do something when saving failed
  end
end
JosephL