How do I create a facebook style news feed in ruby on rails?

后端 未结 3 1598
我在风中等你
我在风中等你 2020-12-12 13:44

I am trying to fuse to objects into a single stream.

I created a new model and controller called Newsfeed. I have it so that newsfeed has_many :messages and has_many

相关标签:
3条回答
  • 2020-12-12 14:01

    This feels like a bit of a loaded question, and though I don't have the time to dig into it in full, here are some initial thoughts for you:

    1. you can combine the two types of items you want to display into a single array and then sort this array based on a field which ought to be common between the two (created_at comes to mind) to get them into chronological order.

    2. In the view, you can use this single collection to iterate over and then use helpers and unique partials to render the items in the correct format. This could be done by checking the objects type as you are trying to display it in the view.

    Something along the lines of:

    if item.is_a? Message
      render :partial => 'message', :locals => {:message => item }
    elsif item.is_a? Image
      render :partial => 'image', :locals => {:image => item }
    end
    

    hopefully this helps some!

    EDIT: to combine the arrays, you can simply append them together using the '+' operator, since arrays in Ruby do not need to contain a single object type.

    your Messages.all and Images.all calls give you arrays of objects, so just try

    @messages + @images 
    

    and you should have your combined array.

    EDIT #2: If I were writing this myself, I would probably handle the views somewhat like this:

    at the top level, simply pass your feeds collection to a partial which is designed to render a single item:

    render :partial => "item", :collection => @feed
    

    this will render the '_item.html.erb' partial for each item in @feed. Also, it will give the partial a local variable named 'item' each time, which is the item in @feed for that particular iteration.

    now, I would probably have the '_item' partial be very simple, like this:

    <%= display_item(item) %>
    

    where display_item is a helper method outside the view and is implemented with the "is_a?" type logic from above to choose the correct display format for the item.

    the reason I would break it up like this is it takes advantage of some nice rails features (pass a collection to a partial instead of looping over the collection yourself) and then pulling the logic out into helpers (or even the models if it makes sense to) is useful because it simplifies your views. keeping logic out of the view whenever possible is generally a good practice as such logic can be hard to test and your views will become very hard to read.

    0 讨论(0)
  • 2020-12-12 14:02

    I'm sure this can be streamlined from it's ghetto-polymorphism, but it works for me, and I had an identical struggle with the "how do I combine all these model results?!"

    I use a separate model, like you, and an observer:

    class NewsfeedObserver < ActiveRecord::Observer
    
      observe Message, Image
    
      def after_save(object)
        @item = Newsfeed.create(
                  :item_id => object.id, 
                  :item_type => object.class.to_s
        )
      end
    end
    

    Then in the Newsfeed model you can pull and collate as you like:

    def self.get_items
      item_list = []
      items = find(:all, :order => "created_at DESC", :limit => 30)
      items.collect{ |i| i.item_type.constantize.find(i.item_id) }
    end
    

    Then just pull them and display in your view however you like.

    #Controller
    def index
      @feed = Newsfeed.get_items
    end
    

    Moving forward I will probably start to pack more into the stream-tracking model in order to save hits on the other tables, but hopefully you get the idea.

    0 讨论(0)
  • 2020-12-12 14:11

    You could do something as :

    controller:

    def index
        messages = Messages.all
        images = Images.all
        @feed = (messages + images).order_by(&:created_at)
    end
    

    view index.html.erb :

    <%= render @feed %>
    

    view _feed.html.erb :

    <% if feed.is_a? Message %>
      <%= render "message", :locals => {:message => feed}%>
    <% else %>
      <%= render "image", :locals => {:image => feed}%>
    <% end %>
    

    And add 2 partials _message.html.erb and _image.html.erb

    0 讨论(0)
提交回复
热议问题