List of users showing the same information - ruby-on-rails

I am showing the subscription information for all users. The issue I have is that it is not displaying the correct information. It is showing the current_user subscription information for all the Users. When it should be displaying each users unique subscription information.
Admin views:
<% #users.each do |user| %>
<li>
<%= link_to user.username, user %>
|<%= #user.subscription.id %>|<%= #user.subscription.plan.name %>| <%= #user.subscription.created_at.strftime("%B %e, %Y") %>
</li>
<% end %>
Admin controller:
def index
#user = current_user
#users = #user.present? ? User.where('id != ?',#user.id) : User.all
render layout: 'new_application'
end
def show
#user = User.find_by(username: params[:id])
end
Error: NoMethodError: undefined method `id' for nil:NilClass

It seems like the template should refer to user, not #user.
Update:
As #rlecaro2 mentioned, it's possible you've got some users with any subscriptions. In the case, calling .subscription on the user variables returns nil and you crash while asking for its id.
<% #users.each do |user| %>
<li>
<%= link_to user.username, user %>
<% if user.subscription %>
|<%= user.subscription.id %>|<%= user.subscription.plan.name %>| <%= user.subscription.created_at.strftime("%B %e, %Y") %>
<% end %>
</li>
<% end %>
Also since you're asking every user for its subscription and later on for the subscription's plan, you should explicitly load these to avoid unnecessary queries. For Rails 4, the Admin controller should look like this:
def index
#users = User.includes(subscription: :plan)
#users = #users.where.not(id: current_user.id) if current_user
render layout: 'new_application'
end
Note that it's not necessary to carry the current_user via #user. You can refer to it in the template directly.

Related

sort by model attribute in controller in user show

I have a book review/discussion site and would like to order all the users books on their profile page based on wether they are currently reading that book. I added a column to the book model called current and when users add a book they can check a box that says "I'm currently reading this." If the user clicks the box then the book object has a :current attribute with a value of "1". If they don't click the box then the value of :current is "0".
In my view I have this code to tell the user which books they are currently reading, and it works fine.
<% if book.current == "1" %>
<h4>I am currently reading this book</h4>
<% end %>
However in my show user controller I can't make it order the incomiing objects by the :current status.
Here's what I've tried:
def show
#user = User.find_by_id(params[:id])
#books= Book.all.sort { |p1, p2| p1.current <=> p2.current }
end
and
def show
#user = User.find_by_id(params[:id])
#books = Book.all
#books = #books.order(:current)
end
and
def show
#user = User.find_by_id(params[:id])
#books = Book.all
#books = #books.order(current: :desc)
end
and, just to make sure it was going the right way
def show
#user = User.find_by_id(params[:id])
#books = Book.all
#books = #books.order(current: :asc)
end
None work. And, none throw errors, they just don't sort it. The "current" book that is last instead of first. Here's the code that displays and loops out the users books. This code also works fine.
<% #user.books.each do |book| %>
<% if params[:id].to_s == book.user_id.to_s %>
<ul class="profileDisplay" >
<img alt="Book Jacket" class="homepageImages" src=<%= book.image %> >
<% if book.current == "1" %>
<h4>I am currently reading this book</h4>
<% end %>
<p><b>Contributor: </b><%= book.user.name %></p>
<p><b>Title: </b><%= book.title %></p>
<p><b>Author: </b><%= book.author %></p>
<p><b>Genre: </b><%= book.genre %></p>
<p><b>Publication Date: </b><%= book.publication_date %></p>
<p><b>Publisher: </b><%= book.publisher %></p>
<p><b>Synopsis: </b><%= book.synopsis %></p>
<% if params[:id] == session[:user_id].to_s || params[:action] == "profile" %>
<%= button_to "Edit Book", book_edit_path(book.id), method: "get", class: "btn btn-primary col-xs-2" %>
<%= button_to "Delete Book", delete_book_path(book.id), method: :delete, data: {confirm: "Are you sure you want to delete this book and all it's reviews?"}, class: "btn btn-danger col-xs-2" %>
<% end %>
</ul>
<% end %>
<% end %>
On view, #user.books are not sorted yet.
You sorted them and assigned it into #books
I think it should be like this
CONTROLLER
def show
#user = User.find_by_id(params[:id])
#books = #user.books.order(current: :desc)
end
VIEW
<% #books.each do |book| %>
<!-- show book records here -->
<% end %>
add default scope in book model
default_scope { order(:current=> :desc) }
and your controller
#user = User.find_by_id(params[:id])
and views
<% #user.books.each do |book| %>
#do whatever
<% end %>

Ruby Twitter gem followers method repeating 20 times rather than displaying first 20 followers

so im using the ruby twitter gem and api in conjunction with omniauth, to log into twitter via a simple rails app, and return the first 20 followers of a user. The main piece of code to do this is a method in a lib file stating:
def followers
client.followers.take(20)
end
For some reason, the app works perfectly locally, but after being deployed to heroku, it displays my first follower, 20 times repeated, as opposed to the first 20 followers. Any help would be appreciated. Here is my code:
I have a basic twitter api app in rails, which works perfectally locally, however when I pushed to Heroku it doesn't work and upon checking the logs there is an error saying uninitialized constant WelcomeController::TwitterApi. I can not find out how to rectify this. Many thanks.
lib/twitter_api.rb
class TwitterApi
def initialize(user)
#user = user
end
def our_public_tweets
client.user_timeline(user, count: 1, exclude_replies: true, include_rts: false)
end
def followers
client.followers.take(20)
end
private
attr_reader :user
def client
#client ||= Twitter::REST::Client.new do |config|
config.consumer_key = Rails.application.secrets.twitter_api_key
config.consumer_secret = Rails.application.secrets.twitter_api_secret
config.access_token = user.token
config.access_token_secret = user.secret
end
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
# to enable the current_user variable to be used in the view file
helper_method :current_user
end
welcome_controller.rb
class WelcomeController < ApplicationController
require 'twitter_api'
def index
#twitter_api = TwitterApi.new(current_user)
end
end
views/welcome/index.html.erb
<div class="wrapper">
<h1>OMNIAUTH AND TWITTER API</h1>
<!-- <%= link_to "Sign in with Twitter", "/auth/twitter" %> -->
<% if current_user %>
<div id="sign_in_wrapper">
<p id="sign_in">Signed in as <span><%= current_user.name %></span> </p>
<%= image_tag current_user.profile_image, class: "profile_image" %>
<p><%= link_to "Sign out", signout_path, id: "sign_out" %></p>
</div>
<div class="public_tweets">
<p>Latest tweet from <%= current_user.name %>:</p>
<% #twitter_api.our_public_tweets.each do |tweet| %>
<% cache('our_public_tweets', expires_in: 6.hours) do %>
<%= parsed_tweet(tweet) %>
<% end %>
<% end %>
</div>
<ul class="followers">
<p>First 20 followers for <%= current_user.name %>:</p>
<% #twitter_api.followers.each do |follower| %>
<% cache('followers', expires_in: 6.hours) do %>
<li><%= follower.name %></li>
<hr>
<% end %>
<% end %>
</ul>
<% else %>
<%= link_to "/auth/twitter", id: "link_button" do %>
<i class="fa fa-twitter fa-3x"></i>
<% end %>
<p class="date">Click the twitter icon to sign in and view followers</p>
<% end %>
</div>
models/user.rb
class User < ApplicationRecord
def self.from_omniauth(auth_hash)
#Look up the user or create them using keys in the auth hash
user = where(provider: auth_hash.provider, uid: auth_hash.uid).first_or_create
user.update(
name: auth_hash.info.name,
profile_image: auth_hash.info.image,
twitter_user_name: auth_hash.info.nickname,
token: auth_hash.credentials.token,
secret: auth_hash.credentials.secret
)
user
end
# token and secret is what came back from omniauth and this was saved to the user database.
end
application_helper.rb
module ApplicationHelper
def parsed_tweet(tweet)
_parsed_tweet = tweet.text.dup
tweet.urls.each do |entity|
html_link = link_to(entity.display_url.to_s, entity.expanded_url.to_s, target: 'blank')
_parsed_tweet.sub!(entity.url.to_s, html_link)
end
tweet.media.each do |entity|
html_link = link_to(entity.display_url.to_s, entity.expanded_url.to_s, target: 'blank')
_parsed_tweet.sub!(entity.url.to_s, html_link)
end
_parsed_tweet.html_safe
end
end
There is your problem, incorrect caching.
<% cache('followers', expires_in: 6.hours) do %>
<li><%= follower.name %></li>
<hr>
<% end %>
When cache is empty, you don't find anything by key "followers". You take first follower and cache it with that key. And by the time you display the second follower, there is a usable cache entry already, so you use the cache, not second follower's data.
Same problem with your other blocks. I think you meant to cache entire loops, not individual elements.
For some reason, the app works perfectly locally
Because locally you have :null cache_store, I think.

Rails 4 conditional render cause N+1 query

I have a grid of posts where a user can like or unlike causing N+1 queries.
I'm rendering a collections of post which partial's has:
<%= post.title %>
<% if current_user.liking?(post) %>
<%= render partial: 'posts/unlike' %>
<% else %>
<%= render partial: 'posts/like' %>
<% end %>
...
User Controller:
def show
#user = User.find(params[:id])
#feed = #user.posts.paginate(page: params[:page])
end
This is causing one query for each post. I though using .include(:likes) but I don't know how to do it for 'current_user'
Edit:
I ended up creating a second query for likes thats belong to current_user
#liking_items = #feed.includes(:likes).where(likes: { user_id: current_user })
Since you have the current_user, you can just add a where:
#user.post.includes(:likes).where(likes: { user_id: current_user })
(I'm assuming that the "like owner" is user_id).

Current_user && User profile

So in my To-do app I have profiles for each user that displays a list of all the Items they have created like so :
<% if current_user %>
<h1>Hello, <%= current_user.username.capitalize%>, </h1>
<% else %>
<h1><%= #user.username.capitalize%> To - Do List. </h1>
<%end %>
<h4> List of Items </h4>
<%= render :partial => 'items/form', :locals =>{:item => Item.new} %>
<% #user.items.order('created_at DESC').each do |item| %>
<%= render :partial => 'items/item' , :locals => {:item => item } %>
<% end %>
My problem is that I want users to be able view other Users profile but with the Header changing according to who is viewing it.
<h1>Hello, <%= current_user.username.capitalize%>, Here is your To-do Items</h1>
if its the current_users own profile or:
<h1><%= #user.username.capitalize%> To - Do List. </h1>
if the user is viewing another users profile.
As you can see I tried a little something with an if statement but it doesn't seem to be working as i want it to .Can anyone help me out please?
Try current_user == #user in if condition.
If there is a possibility that current_user could be nil, then
Try current_user.present? && current_user == #user in if condition.
In your controller you may have:
#user = User.find(params[:id])
Then in your view something along the line of
<% if current_user == #user %>
use this code:
current_user == #user if condition.

Denying unauthorized users from editing a profile

I am trying to setup so that users will get a "not authorized" message if they click edit for a profile that is not theirs. This message should of course not appear for admins since admins can edit all profiles. I previously done this on Permission.rb, however I got rid of the file to go with a more basic user roles/authorization.
I don't see how I can implement what I had previously on Permission.rb for my current files. I have tried some solutions but they don't add up. If someone could point me in the right direction that will be great. Also I am doing this all from scratch, user authentication/authorization.
index.html.erb:
<% #users.each do |user| %>
<li>
<% if current_user.admin? || current_user == #user %>
<% end %>
<%= link_to "Edit #{user} profile", user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?"} %>
</li>
<% end %>
Why are you giving the chance for users to edit other peoples profiles?
First, you should have a if statement in your view where you show the link for the edit page. I guess this is showing up on a profile of every user, so i suppose the code in your controller is something like this:
def show
#user = User.find(params[:id])
end
Then in your view you should have something like this:
<% if current_user.admin? || current_user == #user %>
<%= link_to 'Edit Profile' , edit_user_path(#user) %>
<% end %>
There is also a case if someone tries to 'force' their way in, just like trying to type a url www.yourapplication.com/users/6/edit you could write a before_filter method in your controller:
before_filter :check_privileges, only => [:edit, :update]
and then write a method in called check_privileges
def check_privileges
unless current_user.admin? || current_user.id == params[:id]
flash[:warning] = 'not authorized!'
redirect_to root_path
end
end
EDIT: After the questioner edited his code, i'm showing the mistake:
You are putting the end too soon:
<% #users.each do |user| %>
<li>
<%= link_to user.name, user %>
<% if current_user.admin? || current_user == #user %>
<%= link_to "Edit #{user} profile", user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?"} %>
<% end %>
</li>
<% end %>

Resources