Ask A Question

Notifications

You’re not receiving notifications from this thread.

Liking Posts Discussion

Discussion for Liking Posts

Learned a lot of new things through this post, thank you. Never knew how to properly write a route to a module or the proper architecture for that set up. Very useful stuff. Would have liked to see you use div_for and dom_id methods when it comes to assigning the ids to the p tags and rendering out JS at the end. I feel like both of those are under utilized functions that handle a lot of the hard coded id values, etc...

Reply

It's like you know what's going through my mind. I'm making a dedicated screencast for div_for. ;-)

Reply

Great screencast! I'm behind on my rails development because of a really good Ruby course I'm in, but I will try this out soon. Thank you so much for these!

Reply

Hey! I really appreciate all these screencasts, happily pro user. For this I'm getting an "undefined method 'likes'" on the user model so i'm a little stuck. Any ideas why?

Cheers! :)

Reply

Well, i restarted the server several times and somehow it worked :)

Reply

append

has_many :likes

to user.rb

Reply

Thank you for these screencasts! They are awesome. I keep getting an error "Routing Error uninitialized constant Posts" when I click the 'like' link. I feel like this is a fairly simple fix? Any help would be much appreciated. Thanks in advance.

Reply

If it's in reference to your Post database model (That's my guess) then you want to reference singular "Post" and not plural "Posts" in your controller. Pluralization can get you easily with Rails. :)

Reply

Chris, very useful screencast.

I can get it to work well with just rails, but when I implement ajax I get the following error.

"ActionView::Template::Error (undefined method `likes' for nil:NilClass):"

I've customized it a bit by making polymorphic 'likeable' likes.

Reply

It sounds like your variable that you called ".likes" on was a nil. May need to double check that the find is grabbing the post (or whatever model) is returning the right object.

Reply

Thanks for that screencast. I even watched the forum series and the "polymorphic comments". I m wondering what we do if we want to have likes in our forum for threads and posts? Would you use the polymorphic associations?

Reply

Yep! You can make the likes polymorphic if you want them to apply to more than one model. That would let you add likes to Threads and Posts. You'd build it pretty much the same way and that should do the trick.

Reply

I've got the polymorphic likes working, and even have the ajax version of destroy working, but I can not debug why the create.js.erb isn't working. Rails is telling me I have a routing issue, but rake routes is telling me that I do have this route configured....

Here is the error from development.log

ActionController::UrlGenerationError - No route matches {:account_id=>#<Account id: "def2dbdf-b459-490d-ac41-3f1d1230a1fa", name: "New Co", created_at: "2019-12-28 02:05:01", updated_at: "2019-12-28 02:05:01">, :action=>"destroy", :controller=>"pitches/likes", :pitch_id=>#<Pitch id: 2, title: "Shopability", account_id: "def2dbdf-b459-490d-ac41-3f1d1230a1fa", user_id: "584a1cc3-844d-4b47-9281-dfc520a749b1", created_at: "2019-12-28 23:10:17", updated_at: "2019-12-28 23:10:17">}, missing required keys: [:id]:

Here's my routes...

resources :pitches do
      resources :comments, module: :pitches
      resources :likes, module: :pitches, only: [:create, :destroy]
    end

note: that these are scoped to account ( multitenancy)

I changed the create.js.erb to be a basic alert("create.js.erb called"); but it's not being called. My create method within my pitches::likes controller looks like this,


 def create
    @likable.likes.where(user_id: current_user.id, likable_id: @likable.id).first_or_create
    respond_to do |format|
      format.html { redirect_to [current_account, @likable]}
      format.js {render layout: false}
    end
  end

Any ideas on how to get this to work?

Reply

I finally found the error, it was an error in config/routes.rb. I should have had a singular resource instead of resources, see updated code,

resources :pitches do
      resources :comments, module: :pitches
      resource :likes, module: :pitches, only: [:create, :destroy]
    end
Reply

Chris,

Any idea what query I could put in my user model to find out all posts that have not (yet) been liked by the user?

Reply

The easiest way is to use a counter cache column. It can keep track of how many likes each post has and saves it on the post so that you can quickly and easily query that. There's an old Railscast on it that I'd recommend: http://railscasts.com/episo...

You could also do it with a join and a group by query, but a counter cache will let you sort the information at any time quickly.

Reply

This is awesome! Just the functionality I need. Was looking at the "Act-as-votable-gem" but that seems to be overkill as I only need upvotes. Just need to figure out how the gem does the counter caching stuff now

https://github.com/ryanto/a...

Reply

Hey Chris,

How do I make the before_action :authenticate_user! to work with ajax? If works perfectly, when there is no remote: true and redirects to the login page if a user is not signed in. However, when using ajax, nothing happens other than a "401 unauthorized" in the logs.

Thanks in advance.

Reply

Yeah, that's an issue with redirects and AJAX. jquery_ujs tries to combat that by following the redirect, but it obviously doesn't help since you need to handle that response separately. The simplest solution and what you should generally do is to just disable those links when users are logged out.

If you want to keep them enabled, but then show a sign in form, it's quite a bit more complex and would require you to write your own handler in JS to capture that response and handle it separately.

Reply

Hey Chris,

First of all, thank's for the quality of your video.

Unfortunately I'am stuck in the middle of the video, i'am facing with this error : undefined method `likes' for, it highlights

<% if user_signed_in? && current_user.likes?(@pin) %>

@pin is the name for post in my app.
def likes? is written in the User model, could you explain why ?

Cheers

Reply

According to the error, it sounds like maybe you don't have "has_many :likes" set up in your User model correctly so it can't find it. Double check that you've got that in there.

And "likes?" is written in the User model as a cleaner syntax for determining if the user likes a an object. Basically you wouldn't want to have the logic for determining that duplicated in your app everywhere, so we put it in a method in the model to make it more readable everywhere else.

Reply
Kohl Kohlbrenner Kohl Kohlbrenner

@excid3:disqus I have a likes partial inside of a parent directory like this: app/views/recipes/likes/_like.html.erb. I am trying to render inside the show action of the recipes controller and I am getting an error: missing partial: app/views/recipes/likes/_like. I'm not sure what is throwing the error.
likes partial below:

<% if @recipe.liked_by?(current_user) %>
<%= link_to "Unlike", recipe_like_path(@recipe), method: :post %>
<% else %>
<%= link_to "Like", recipe_like_path(@recipe), method: :post %>
<% end %>

In my Recipes::LikesController create action:

@like = Like.where(user_id: current_user.id, recipe_id: @recipe.id)
if @like.nil?
@like = @recipe.likes.where(user_id: current_user.id).first_or_create!
@recipe_was_liked = true
else
@like.destroy
@post_was_liked = false
end

Reply
Kohl Kohlbrenner Kohl Kohlbrenner

whoops. I figured it out!

Reply

Been looking for a way to do this for a while, great episode...now how would I list all the all the posts that a user has liked? For example, I can do something like this:
<ul>
<%= current_user.owns(@book).each do |book| %>
<li><%= book.id.to_s %></li>
<% end %>
</ul>

...but alas this only shows me the own.id whereas I would like it to show me, for example the book.title. Also, this works with the show action, but in my index it doesn't as I have set up a <% @book.each do |title| %>. I can place the code inline, replacing @book with title but then my ajax button change is rendered useless. I'm fairly new to Rails so any ideas would be welcome!

Reply

You can set up an association to get the liked books through the likes the user has. It follows basically the same format. Remember that your book variable from the each is actually a full Book record so you can print out the id, the title, or whatever just by changing what you reference. Here's an example that would list out the book titles that a user likes. (I haven't tested this so it may not work right off the bat)

class User
has_many :likes
has_many :liked_books, through: :likes, class_name: "Book"
end

<%= current_user.liked_books.each do |book| %>
<li><%= book.title %></li>
<% end %>

Reply
Kohl Kohlbrenner Kohl Kohlbrenner

getting an ActionController::RoutingError (uninitialized constant Pins) error in the logs. Can seem to figure it out

Routes are nested like so:

resources :pins do
resource :like, only: [:new,:create, :destroy], module: :pins
end

In Index View- this is pins/likes/like partial

<% if current_user.likes?(pin) %>
<%= link_to "", pin_like_path(pin), method: :delete, class: "fa fa-pinterest-p like", remote: true %>
<% else %>
<%= link_to "", pin_like_path(pin), method: :post, class: "fa fa-pinterest-p ", remote: true %>
<% end %>

Then I have this nested controller with create and destroy actions
class Pins::LikesController < ApplicationController
...
end

Reply
Kohl Kohlbrenner Kohl Kohlbrenner

fixed it renamed folder from pins_controller to pins

Reply
Kohl Kohlbrenner Kohl Kohlbrenner

My ajax isn't firing. I am getting an ActionView Template error, undefined local variable or method 'pin'

After I refresh the glyphicon changes color signifying it hit the db. In my index I have <%= render partial: 'pins/likes/like', locals: {pin: pin} %> and the guts of the partial is in my comment below. The partial sits in the block:
@pins.each do |pin|
...
end

Any ideas off the top of your head?

Reply

Should it be locals: {pin: @pin} instead? I'm assuming you are just missing sending the pin from the controller.

Reply

I've been playing with joins but can't seem to find the answer: I can displayed a user's liked posts (current.user.liked_posts.each do) but they are sorted by the creation date of the post. How can I sort by the like.created_at date?

Reply

You can do a SQL ORDER on the created_cat column by adding liked_posts.order(created_at: :desc) or :asc if you want ascending.

Reply

where is the github?

Reply

can i have the source coe for this?

Reply
Reply

Interested to see the source code!

Reply

@excid3:disqus Thanks for implementing with basic functionality. I have few questions:

1. On index pages to show all posts, it will have N+1 to check if the current_user like each post. Is there any good way to remove that?
2. I know we could eager load with `includes(:likes)` to solve N+1, just imagine if we have many likes for each post, and we just want to show the total count, and the last 3 likers either radom or from last, how do we do eager load them and prevent to load entire likes collection from db?

Reply

The best way is really to load up all the user's likes for those related objects in a single query. Then you can check those post against the likes result with Ruby and that will be 2 queries instead.

You'll have to do some custom SQL to pull off #2, but it's not so bad. Check this out: https://robots.thoughtbot.c...

Reply

@excid3:disqus I am not yet a paid member so I couldn't see this screencast yet, I just have one question though. Is this the kind of "LIKE" that the page will not refresh? Because I only knew acts_as_votable now but my problem is if I click the upvote button, the page will refresh.

Reply

Yep! It's all AJAX based and includes showing avatars and stuff if you wanted to show a few people's faces who liked the post as well.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 85,376+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.