Gravatar - Undefined method 'email' for nil:NilClass - ruby-on-rails

I've set up gravatar and have got it working for my 'users/*user id goes here*'.
But whenever I try to use it in dashboard/index that's whenever it gives me the error
Undefined method 'email' for nil:NilClass
My dashboard controller is :
class DashboardController < ApplicationController
def index
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
end
Dashboard View :
<div class="dash-well">
<div class="gravatar-dashboard">
<%= image_tag avatar_url(#user), :class => 'gravatar' %>
<h1 class="nuvo wtxt"><%= current_user.username.capitalize %></h1>
</div>
</div>
My Application Helper :
module ApplicationHelper
def avatar_url(user)
default_url = "#{root_url}images/guest.png"
gravatar_id = Digest::MD5.hexdigest(user.email.downcase)
"http://gravatar.com/avatar/#{gravatar_id}.png?s=200{CGI.escape(default_url)}"
end
def avatar_url_small(user)
default_url = "#{root_url}images/guest.png"
gravatar_id = Digest::MD5.hexdigest(user.email.downcase)
"http://gravatar.com/avatar/#{gravatar_id}.png?s=40{CGI.escape(default_url)}"
end
end
My user model :
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :user_id, :id, :website, :bio, :skype, :dob, :age
has_many :posts
# attr_accessible :title, :body
end
My Dashboard Model :
class Dashboard < ActiveRecord::Base
attr_accessible :status, :author, :email, :username, :id, :user_id, :user, :website, :bio, :skype, :dob, :age
belongs_to :user
end
Sorry, i'm pretty new to Ruby-On-Rails!

Try this:
<%= image_tag avatar_url(current_user), :class => 'gravatar' %>

You really want this in your controller:
def index
#user = current_user
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
Note the addition of the second line, which assigns the #user variable to the current_user.
Then, the #user you are calling in your view will work. A typical rails pattern that you'll see emerge as you continue to use it is that most variable that begin with the # symbol will be defined in the corresponding controller method for that view. So, if you are using a variable with #, and it's not available, check the controller to ensure it's defined first. (FYI these are called instance variables if you want to learn more).
To address a second concern, if you are current_user and you wanted to visit another user's page:
def show
#user = User.find params[:id]
respond_to do |format|
format.html # index.html.erb
format.json { render json: #user }
end
end
This would work with a URL like /users/1, you can use that very same call to avatar_url, pass the #user, and it will get that user's avatar, where the user is the one that matches the given user ID. You probably already have this exact code in your controller already, but hopefully now you see why it works.
Good luck!

Related

Pg_Search don't filter model referenced to another

I'm renewing a small library app and my search filter (pg_search) doesn't work with a model that is referenced with another (in this case, model Book as User references, for each user to have it's own set of books).
But if i delete the references, the search works... In the case that if the books were available to every user but that's not the purpose.
What am i missing?
Thanks in advance for any help.
Book.rb
class Book < ApplicationRecord
belongs_to :user
include PgSearch::Model
pg_search_scope :search_by_full_name, against: [:title, :author],
using: { tsearch: { prefix: true } }
validates :title, presence: true
validates :author, presence: true
end
User.rb
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :books
end
books_controller.rb
class BooksController < ApplicationController
def index
if params[:term].present?
#books = Book.search_by_full_name(params[:term])
else
#books = Book.all
end
end
def show
#book = Book.find(params[:id])
end
def new
#user = User.find(params[:user_id])
#book = Book.new
end
def create
#user = User.find(params[:user_id])
#book = Book.new(book_params)
#book.user = #user
if #book.save
redirect_to user_books_path
flash[:notice] = 'Success. Your book was added to the Library'
else
render "new"
flash[:notice] = 'Book not created. Please try again'
end
end
def edit
#user = User.find(params[:user_id])
#book = Book.find(params[:id])
end
def update
#book = Book.find(params[:id])
#book.update(book_params)
redirect_to user_book_path
end
def destroy
#book = Book.find(params[:id])
#book.destroy
redirect_to user_books_path
end
private
def book_params
params.require(:book).permit(:title, :author, :photo, :comments)
end
end
_search_book.html.erb
<%= form_tag user_books_path(current_user.id, #book), method: :get do %>
<%= text_field_tag 'term', params[:term], placeholder: "Enter title or author" %>
<%= submit_tag 'Search!' %>
<% end %>
It's solved... I was using current_user on the views instead of applying all the method on the controller and on the view leave it with only the model instance.
Thanks everyone

Rails comments and username won't show up in post views / undefined method `user' for nil:NilClass

So I have a post.rb model where I can display who wrote the post in the show post view, and that works wonderfully.
However, I've been trying to add comments, which belong to a post, and also belong to a user.
I can't seem to get all the comments or the names of the users who posted the coments to show up in the post show.html.erb.
I guess my question is, how do I integrate controller and model information in between controller and model views? I know if it exists in the model and controller and view of the same type, it is accessible, but cross-linking or sharing controller model information is hard for me.
I want to be able to display the user that made the comment, along with the body of the comment in the show view of the post, and not the comment.
comment.rb
class Comment < ApplicationRecord
belongs_to :post
belongs_to :user
validates :body, :presence => true
end
post.rb
class Post < ApplicationRecord
belongs_to :user, optional: true
validates :user, presence: true;
validates :title, presence: true,
length: { minimum: 5}
extend FriendlyId
friendly_id :title, use: :slugged
validates :title, :slug, presence: true
# comments
has_many :comments
end
user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :first_name, presence: true
validates :last_name, presence: true
validates :school_name, presence: true, inclusion: { in: %w(Harvard Yale),
message: "%{value} is not a valid choice" }
validates :graduation_year, presence: true, inclusion: { in: %w(2017 2018 2019 2020 2021 2022 2023),
message: "%{value} is not a valid choice currently" }
def superadmin?
self.role.name == "Superadmin"
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :authenticate_user!
# GET /posts/:post_id/comments
# GET /posts/:post_id/comments.xml
def index
#1st you retrieve the post thanks to params[:post_id]
post = Post.friendly.find(params[:post_id])
#2nd you get all the comments of this post
#comments = post.comments
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #comments }
end
end
# GET /posts/:post_id/comments/:id
# GET /comments/:id.xml
def show
#1st you retrieve the post thanks to params[:post_id]
post = Post.friendly.find(params[:post_id])
#2nd you retrieve the comment thanks to params[:id]
#comment = post.comments.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #comment }
end
end
# GET /posts/:post_id/comments/new
# GET /posts/:post_id/comments/new.xml
def new
#1st you retrieve the post thanks to params[:post_id]
post = Post.friendly.find(params[:post_id])
#2nd you build a new one
#comment = post.comments.new(params[:comment])
#comment.user = current_user
end
# GET /posts/:post_id/comments/:id/edit
def edit
#1st you retrieve the post thanks to params[:post_id]
post = Post.friendly.find(params[:post_id])
#2nd you retrieve the comment thanks to params[:id]
#comment = post.comments.find(comment_params[:id])
end
# POST /posts/:post_id/comments
# POST /posts/:post_id/comments.xml
def create
#1st you retrieve the post thanks to params[:post_id]
post = Post.friendly.find(params[:post_id])
#2nd you create the comment with arguments in params[:comment]
#comment = post.comments.create(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
#1st argument of redirect_to is an array, in order to build the correct route to the nested resource comment
format.html { redirect_to([#comment.post, #comment], :notice => 'Comment was successfully created.') }
#the key :location is associated to an array in order to build the correct route to the nested resource comment
format.xml { render :xml => #comment, :status => :created, :location => [#comment.post, #comment] }
else
format.html { render :action => "new" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
end
In the show method of your post_controller, you'll need to do something like:
def show
#post = Post.find_by(id: params[:id]) # or however you find your post
....
end
Then, in your views/posts/_show.html.erb (if you're using erb), you'll do something like:
<% #post.comments.each do |comment| %>
... show some comment stuff
<%= comment.user.name %>
<% end %>

Devise: Can't mass-assign protected attributes: email, name

I'm using Rails (3.2.3) and Devise, and allowing administrators to create new users – and edit user accounts.
At this point, administrators can create accounts successfully. However, they can't edit them.
When you try to edit a user's account, a mass-assignment error is raised:
Can't mass-assign protected attributes: email, name
Even though, in the User model, these attributes are set to accessible:
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
What's interesting, is, if I change the above line to attr_protected, you CAN edit user information but you CANNOT create users anymore. Very weird.
Here's the relevant code I'm working with... any help is appreciated.
User model:
class User < ActiveRecord::Base
rolify
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :role_ids, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
end
Users controller:
class UsersController < ApplicationController
before_filter :authenticate_user!
def update
authorize! :update, #user, :message => 'Not authorized as an administrator.'
#user = User.find(params[:id])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if #user.update_attributes(params[:user], :as => :admin)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
end
Change to
class User < ActiveRecord::Base
rolify
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :role_ids, :name, :email, :password, :password_confirmation, :remember_me, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
end
Now administrators can create accounts successfully & they CAN edit them as well. Hope it helps

Displaying attributes for associated models in views

I want to fetch username or email( both are in user table) of user who creates article in blog application. Currently I am able to fetch user id from articles_controller.rb
def create
#article = Article.new(params[:article])
#article.user_id = current_user.id
#article.save
redirect_to article_path(#article)
end
but no idea how to fetch username or email for same. Basically I want to display username or email on article index page. Please suggest me to how to get done it
user.rb
class User < ActiveRecord::Base
has_many :articles
has_many :comments
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
attr_accessible :title, :body
end
article.rb
class Article < ActiveRecord::Base
attr_accessible :title, :body
has_many :comments
belongs_to :user
end
articles_controller.rb
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(params[:article])
#article.user_id = current_user.id
#article.save
redirect_to article_path(#article)
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to action: 'index'
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
#article.update_attributes(params[:article])
flash.notice = "Article '#{#article.title}' Updated!"
redirect_to article_path(#article)
end
end
article/index.html.erb
<div style="color:#666666; margin-top:10px"> <%= article.created_at %></div>
<div style="color:#666666; margin-top:10px"> <%= article.user_id %></div>
Articles table
class CreateArticles < ActiveRecord::Migration
def change
create_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
add_index :articles, [:user_id, :created_at]
end
end
I am able to fetch user id in views but no idea how to username or email.
Any help would be appreciated.
You have defined a user association on your Article model class with belongs_to :user. This creates a user method on Article that returns the associated user so you in your view:
<%= article.user.email %>
will output the email of the associated user, or:
<%= article.user.email if article.user %>
to cater for nil user values. Alternatively write a helper to factor this logic out of the view.
Already you set relation between the Article & User model. So in your article index page you have all articles in #articles variable. So easily you can get the particular user of a particular article using below code,
#articles.each do |article|
user = article.user #gives the user of this current article. From this
#objecct you can easily get the username, email or everything specific to user.
email = user.email #gives email of article's user or you can directly give artile.user.email
end
like this you can get all the attribute of user.

accepts_nested_attributes_for giving error: Can't mass-assign protected attribute

I'm getting 'Can't mass-assign protected attribute' error when trying to save a form that uses 'accepts_nested_attributes_for'. I think I have code the model correctly but not sure what I missed. Any idea?
error: Can't mass-assign protected attributes: organization
user.rb
class User < ActiveRecord::Base
belongs_to :organization
accepts_nested_attributes_for :organization
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me,
:username, :first_name, :last_name, :organization_attributes
end
organization.rb
class Organization < ActiveRecord::Base
has_many :users
attr_accessible :address1, :address2, :city, :country, :fax, :name, :phone, :state, :zip
end
users_controller.rb
def new
#user = User.new
#organization = Organization.new
respond_to do |format|
format.html # new.html.erb
end
end
def create
#user = User.new(params[:user])
#organization = #user.organizations.build(params[:organization])
respond_to do |format|
if #user.save
#organization.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
Manage to get what I want based on the answer on this question: Use both Account and User tables with Devise
By the way I'm also using STI and it works great.

Resources