Displaying related entries by tags - HELP!

Ok, my site is setup like pretty much every other blog out there. A
list of the most recent 5 posts, then by clicking one, you go to an
individual post page, displaying the full context of that post.

Now, what I would like to do is to display the related entries in the
side column, which is part of the layout, based on the tags belonging to
that specific entry.

Here’s my coding so far:

#view
<% for post in @posts %>

<%= post.title %>

tags: <%= post.tags.collect { |tag| link_to tag.name, :controller =>
“articles”, :action => “by_category”, :category => tag.name.to_s
}.join(", ") %>

<%= post.entry %>

<% end %>

#layout
<% for related in @contents_related %>

  • <%= related.title %>
  • <% end %>

    #controller (how do I pass the tag_id and the content_id?)
    @contents_related = Content.show_related_entries(?,?)

    #model
    def self.show_related_entries(t_id, c_id)
    find_by_sql(“select c.title from contents c inner join contents_tags
    ct on c.id = ct.content_id where ct.tag_id = #{t_id} and c.id !=
    #{c_id}”)
    end

    The function works if I manually pass a content_id (for my entry) and a
    tag id (for a tag of that entry). Now, how can I dynamically pull out
    the single content_id for the post, but execute the function for each
    tag related to that individual post???

    Hopefully you can see what I’m trying to accomplish, and can have a
    suggestion (even if it’s completely different) as to how I can get this
    working!

    Thanks for any help!

    Am Montag, den 13.03.2006, 04:50 +0100 schrieb ryan:

    #view

    find_by_sql("select c.title from contents c inner join contents_tags 
    

    suggestion (even if it’s completely different) as to how I can get this
    working!

    Thanks for any help!

    Hi Ryan,

    your message is a little confusing, because of these mass of different
    names you use. Names you have in your code or talking about are: post,
    tag, entry, category, related, content, related_content,
    related_entries, contents_tags

    I am not sure what you title content and entry within a blog. What i
    would expect is post, comment, tag (or keyword). What are
    related_contents and entries? Where is the difference between content
    and entry? Maybe you can do a little refactoring.

    Please clarify this and try to describe your problem again. If i would
    understand it, i probably could help you.

    Ciao,
    Norman

    Norman T.

    http://blog.inlet-media.de

    Yes, I understand what you mean, it is confusing. Ok, basically, all I
    want to do is pull a list of related entries which will be displayed in
    the layout in a column to the right, but it must be based on the current
    entry loaded into the view.

    I can write a sql query to accomplish this, but I don’t know how to get
    the id of the tag (and there will be multiple tags to check, so I need a
    loop?) as well as the id of the post (or entry).

    The way I load my posts is with a for loop. So, in words, I do this in
    the view:

    #view
    <% for [variable_name] in [@class_variable_holding_the_data] %>
    <% [variable_name].title %>

    #get the tags
    <% [table_name].tags.collect {|tag| tag.name} %>

    <% end %>

    Now, the @class_variable_holding_the_data, in this case, is one entry
    based on a permalink. I need to pass that ID along with some sort of
    loop to get all of the tag IDs, and display this in the layout.

    I’m still probably confusing you really bad, but maybe you can now see
    what I’m trying to do. If not, it’s ok, i’m not very good with
    explaining stuff.

    Basically, I want to pull related entries in the layout based on any
    number of tags for an individual entry loaded into the view. If you
    know a better way, I’m open for suggestions. Thanks!

    Yes, that’s exactly what I’m trying to do, and I like your suggestions
    very much. That was my original intention, but lack of experience let
    me come up with it. Now, I’m trying to follow what you said to try, and
    I’m getting a “no method” error for ‘related_entries’.

    Is it possible to use the permalink to get the individual entry instead
    of the id? Like so:

    EntriesController < ApplicationController
    def show
    @entry = Entry.find_by_permalink(params[:permalink])
    @related_entries = @entry.related_entries
    end
    end

    That’s what I’m trying. The method ‘related_entries’ is defined in the
    Tag.rb file, is that what you intended?

    You said to add a “find” method in my entry model, but then defined
    ‘related_entries’ in the tag model.

    You obviously know what you’re talking about, but I’m new at all of
    this, so I’m still somewhat confused.

    Any suggestions?

    Am Montag, den 13.03.2006, 14:31 +0100 schrieb ryan:

    the view:
    Now, the @class_variable_holding_the_data, in this case, is one entry
    based on a permalink. I need to pass that ID along with some sort of
    loop to get all of the tag IDs, and display this in the layout.

    I’m still probably confusing you really bad, but maybe you can now see
    what I’m trying to do. If not, it’s ok, i’m not very good with
    explaining stuff.

    Basically, I want to pull related entries in the layout based on any
    number of tags for an individual entry loaded into the view. If you
    know a better way, I’m open for suggestions. Thanks!

    Ok, i try to replay this:

    You have a many-to-many association Entry ↔ Tag.

    Now you want to get all the entries, that share the same tags of a
    specific entry, right?

    Add a find method to your entry model, that does the magic. Don’t do
    this in the view. Another place may be the controller, but for finders
    use the model.

    class Tag < ActiveRecord::Base
    has_and_belongs_to_many :entries

    def related_entries
    tags.collect { |tag| tag.entries }.flatten.uniq
    end
    end

    class Entry < ActiveRecord::Base
    has_and_belongs_to_many :tags
    end

    Perhaps this solution might be a little bit slow, if you have a lot of
    data. Try using this find method:

    class Tag < ActiveRecord::Base
    has_and_belongs_to_many :entries

    def related_entries
    tag_ids = tags.collect { |tag| tag.id }
    Entries.find(
    :all,
    :include => tags,
    :conditions => [‘tag.id IN (?)’, tag_ids.join(‘,’)]
    )
    end
    end

    No matter what way you go, you don’t have to deal with ids:

    view

    <% for entry in @entries %>
    <% entry.title %>

    get the related entries

    <% for related in entry.related_entries %>
    <%= related.title %>
    <% end %>
    <% end %>

    The perfect way would be to preload the related entries in your
    controller and put them into an own instance variable, so if you need
    them twice in a view, they are only loaded once.

    EntriesController < ApplicationController
    def show
    @entry = Entry.find(params[:id])
    @related_entries = @entry.related_entries
    end
    end

    This is the best way, if you want the related entries linked in a
    sidebar. In your sidebar view just test if the @related_entries is not
    nil and then iterate over them and spit out links.


    Norman T.

    http://blog.inlet-media.de

    Am Montag, den 13.03.2006, 18:52 +0100 schrieb ryan:

    @entry = Entry.find_by_permalink(params[:permalink])
    @related_entries = @entry.related_entries
    end
    end

    Sure, the code above should work as expected.

    That’s what I’m trying. The method ‘related_entries’ is defined in the
    Tag.rb file, is that what you intended?

    No, the related_entries method should be defined in the Entry model, as
    it is finding Entry models. The method is finding related entries, that
    share the same tags as the entry, on wich you call the related_entries
    method.

    You said to add a “find” method in my entry model, but then defined
    ‘related_entries’ in the tag model.

    It is a find method without the find word in the method name :wink: Call it
    find_related_entries, if you like. It’s just a naming thing. Sorry for
    the confusion.

    You obviously know what you’re talking about, but I’m new at all of
    this, so I’m still somewhat confused.

    Hope that helps.

    Norman T.

    http://blog.inlet-media.de