The site is a simple community where each user creates posts and users may "like" them or "unlike" them.
I have a Post and a Like model. Currently, I'm listing all posts and also the likes size for each post through post.likes.size . The button to like a post is also working.
What i don't know how to do is how to depending on the case, if a post should show the unlike button or the like (depending if the current_user already liked that post).
The like model is very simple:
User_id // current user
Post_id // post to associate
Thanks in advance!
You should define association in user model
if it's ror 2.* add method in User model. it should look like this:
has_many :likes
def already_likes?(post)
self.likes.find(:all, :conditions => ['post_id = ?', post.id]).size > 0
end
Assuming Like has fields user_id and post_id
and of course in view
if current_user.already_likes?(#post)
#add unlike button
end
You want to search for a record that matches the user_id and post_id. If you find one, you want to show the 'unlike' button, b/c that means the user has 'liked' the post already. If you don't (it returns nil), you want to show the 'like' button.
The following method returns nil if the user hasn't 'liked' the post, and not nil if the user has 'liked' the post.
def user_likes(current_user, post_id)
likes.find(:first, :conditions => ['user_id = ? AND post_id = ?', current_user, post_id] ).nil?
end
So you can say:
if user_likes(1, 12).nil?
# show like button
else
#show unlike button
end
Also you could add validation to your Like model like so:
validate :user_does_not_already_like_post
def user_does_not_already_like_post
errors.add(:user, "You can only like a post once.") if user.already_likes?(post)
end
create an action like this in your posts controller.
def unlike
# get the post
#code to decrement the like counter of a specific post
end
then from your view, create a button or a link that points to this action.
Related
In my application I've a button called Interested. When this button is clicked it'll add a record to interests table with user_id & post_id.
This is My PostsController:
class PostsController < ApplicationController
def interested
#interest = Interest.new
#interest.user_id = params[:user_id]
#interest.post_id = params[:post_id]
#interest.save
end
My routes.rb
get 'i/:user_id/:post_id', to: 'posts#interested', as: :interested
My show view:
= link_to "Interested", interested_path(post.id, current_user), remote: true
How can I make it so when it's clicked it adds the record to my table & if clicked twice, it removes the record from table (as if they are not interested anymore)
From what I understood, the first time a user clicks "interested" on a post you want to save that as a post the user is interested in. However when the user clicks "interested" once again on a post he already marked as interested then you want to delete the record.
This is one way to achieve that:
def interested
#interested = Interest.find_by(user_id: params[:user_id], post_id: params[:post_id]
if #interested
#interested.destroy
else
Interest.create(user_id: params[:user_id], post_id: params[:post_id])
end
end
You'd also want some sort of flash message to indicate that the interest has successfully been created/destroyed
You could have 2 link_to buttons, one for "interested" and one hidden for "not interested". The 2 buttons could go to their own action in the controller: interested-action and a not_interested-action. Then you get a nice seperation of concerns in handling the database part of things. The 2 buttons are of course toggled in javascript/jquery in click event handlers using show/hide method.
In the interested-action on the server you should use the find_or_create_by method to get hold of the record. Then on the record should be a field "active" set to true determining whether the user is interested. In the not_interested-action this field is simply set to false.
I am trying to get access to a property contained inside my user object.
My user model has_many: posts. In the controller how would i gain access to these posts? Would i create a method in the model?
def posts
#posts = Post.find(User_id: params[:id])
end
or can i directly access the posts for the user. User.posts Since i am currently residing in the controller, is the controller aware of the currently selected model? Or do i have to pull the information again?
You can query the database for all the posts with a specific user_id, like this:
#posts = Post.where(user_id: params[:id])
Alternatively, you can find the user first and then fetch all posts associated with that user, like this:
user = User.find(params[:id])
#posts = user.posts
Assuming your id in params is the id of your user, you can use user = User.find(params[:id]) to get the user and #posts = user.posts to get all the posts of this user.
So, it is not about where you are, It is about what you are calling.
I'm sure you are familiar with relationships...
When you have relationships, it means that you can get to one relation from the other through whatever association exists between them.
If I am my father's son, then you can get me directly by checking my father's children. ( you don't necessarily have to get all children in the village first )
So, bringing all my story above together, with the association between your Post and User, you can always call user.posts (user being an instance of User) and post.user ( with post being an instance of Post)
The Ruby on Rails guides have a section on associations, which is what you want. It's here: http://guides.rubyonrails.org/association_basics.html
In a nutshell, because you have added an association in your user model to a number of post records, Rails will build a helper method in your user model called posts. You can use that to access all the posts associated with that user.
When you create a post, the post record needs to have a column called user_id. This will provide the 'physical' link between the user and post models. You can access the posts from a user like so:
user.posts each do |post|
# do something with post.content
end
To get posts that match some criteria in the posts collection you can query like this:
posts = user.posts.where(:something => 'matches criteria')
If you know there's only one post that matches the criteria, you can do this:
post = user.posts.where(:something => 'matches criteria').first
The post model also needs a belongs_to :user association. (The belongs_to will generate a helper method called user in the post model which you can then use to access the user record from the post.) For example:
user_email = post.user.email
The user record does not require a post_id column since Rails knows that user.post refers to the post table and automagically generates a query using user_id.
Anyway, the guide I linked to above will give you all the information you need and more too.
Class User
has_many :posts
end
Class Post
belongs_to :users
end
I have a post's content and would like to find out if a user ever sent a post with the same content. I could find it out easily if I was only searching against a single user.
user.posts.exists?(content: params[:content])
I would like to look through all the users in the DB.
users = Users.all
users.posts # will not work NoMethodError: undefined method `posts' for #<Array:0x007fbe818fbd98>
I need either a true as soon as there is a single match or a false if there is no user with matching content, for all the posts posted from all the users.
I could always loop this in a block and get a result this way, is there a way of doing this in a single line of code?
Try something like this:
posts = Post.where(content: params[:content])
users = User.find posts.map(&:user_id)
Or a shorter one:
users = User.find Post.where(content: params[:content]).pluck(:id)
Or if you just need to check whether a post (created by any user) with a given content exist:
Post.exists?(content: params[:content])
I am using ActiveAdmin and i want to list items which belong to a specific user. The two resources have the has_many and belongs_to relationship.
An index pages is listing all the users. Now i would like to render a show block for each user his items.
My show looks now something like this:
ActiveAdmin.register User do
show do
panel "Specific Item List" do
table_for Item.where("user_id=1").fnidi_each do |i|
column("ID"){|item|item.id}
column("Name"){|item|item.name}
end
end
end
end
How do i inherit the user_id from the page to the show panel ? So that each time show is called i can use the users id for the query.
I know these a basic question but my knowledge of Rails/AA is so far quite basic as well ;) Happy for any advice.
Looking at this code from the ActiveAdmin documentation, where "post" seems to be dynamically generated within the register block suggests that in your case you may be able to just do "user.id", etc.
ActiveAdmin.register Post do
show do
h3 post.title
div do
simple_format post.body
end
end
end
So you might try user.items or Item.where(user_id: user.id) instead of your Item.where("user_id=1").
I'm currently developing an application whereby a user clicks a button and they're offered up a new page of content, and was wondering how I would go about hiding or skipping past those that the user has already interacted with (a separate table stores the post_id and user_id for each view).
I currently use this code in the model for displaying a random page:
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
The user authentication system is built off of Authlogic, and I have User, Post and View models.
So if a user has already seen a post "foo", how would I not display that in the future and instead serve up a random "bar".
Thanks
Steve,
I would set a boolean field for each post called "read" (default => false).
Upon firing the "show" action of your controller (and any other action you consider the person seeing the post), you can automatically set that to true and perform a save without validation. When you then show your list of records, you can add the condition .where("read = ?", false).
Of course, you can decide whether you want to give users the flexibility of setting individual posts to 'unseen' or 'unread' - if you want to do that it's the subject of another question :).
You could store an array of viewed post ids on the session in the show action of the posts_controller. EDIT -- find random post not already viewed. Not tested, but the idea is here:
def show_random_post
while (id == nil || (session[:viewed_posts] ||= []).include?(id)) # initialize array if it hasn't been initialized
id = rand(Post.count) + 1
end
session[:viewed_posts] << id
#post = Post.find(id)
# etc.
end
Do you want to keep a record of viewed posts between sessions?
EDIT: If you want to keep a user-level record of viewed posts between sessions, you'll probably want to do it at the db level. Since this means a many-to-many relationship between users and posts, you'll likely want to manage that with a relational table, and the best way to do that in Rails is with has_many :through. Something like (again, not tested):
class ViewedPostRecord < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
class User < ActiveRecord::Base
has_many :viewed_post_records
has_many :viewed_posts, :class => 'Post', :through => :viewed_post_records
end
class PostsController < ApplicationController
def show_random_post
while (id == nil || current_user.viewed_posts.map(&:id).include?(id))
id = rand(Post.count) + 1
end
#post = Post.find(id)
current_user.viewed_posts << #post
# etc.
end
end