Rails 4 - how to get user name from their id - ruby-on-rails

I have a order show page shown below. I had this working but ever since I changed computers to work on this app, the name did not display.
If I change <%= #order.user.name %> to <%= #order.user.id %>, I get the correct id. Otherwise I get nothing displaying where as the name of the id should be posted.
#view/orders/show.html.erb
<p>
<strong>Code:</strong>
<%= #order.code %>
</p>
<p>
<strong>Client:</strong>
<%= #order.client.name %>
</p>
<p>
<strong>User:</strong>
<%= #order.user.name %>
</p>
<p>
<strong>Notes:</strong>
<%= #order.memo %>
</p>
<p>
<strong>Status:</strong>
<%= #order.status ? "Confirmed" : "In Progress" %>
</p>
<%= link_to 'Edit', edit_order_path(#order) %> |
<%= link_to 'Back', orders_path %>
#models/order.rb snippet
class Order < ActiveRecord::Base
belongs_to :user
end
#model/user.rb
class User < ActiveRecord::Base
has_many :orders, dependent: :destroy
has_many :addresses, dependent: :destroy
has_many :telephones, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :manager, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
end
#controllers/order_controller.rb snippet
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end

I think I just answered another question of yours, but I would recommend using the .delegate method like this:
#app/models/order.rb
Class Order < ActiveRecord::Base
belongs_to :user
delegate :name, to: :user, prefix: true #-> #order.user_name
end
You can delegate multiple variables if you need to.
This fixes Law of Dementer, as described here

As mentioned in comments, the value for the user name is empty and that is why it displays a blank when looking for the name.
Adding a name(string) to the user.name will solve the issue
When using a different database, make sure to also update the database with data, preferably the same data which initially tested with.

It's completely independent of the machine you use, so there have to be some changes you've made in your code that you don't remember.
Check what value is returned when you call this user from the console. Type rails c in the terminal and then type a command:
User.find(<<ID_OF_USER_WHOES_NAME_IS_NOT_DISPLAYED>>).name
If its name is empty, it could be a problem with creating a user or something.
Make update when you'll check it.

Related

Model does not seem to be getting saved?

So I am using the devise gem to generate users for my web app. I have a Business model that is a has_one: association with my User. When I attempt to create a business when logged into my user it simply does not save it. Also when i use rails console in the terminal attempting to open up my Business model returns nil. In the view that is calling .business on the user shows nothing
Here is my business model
class Business < ActiveRecord::Base
belongs_to :user
end
User Model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :name, presence: true
has_many :posts, dependent: :destroy
has_one :business, dependent: :destroy
has_attached_file :avatar,
styles: { medium: "300x300#", thumb: "100x100#", post_pic: "44x44" },
default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end
Business controller
class BusinessesController < ApplicationController
before_action :set_business, only: [:show, :edit, :update, :destroy]
def index
#businesses = Business.all
end
def show
end
def new
#business = current_user.build_business
end
def edit
end
def create
#business = current_user.build_business(business_params)
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render :new
end
end
def update
if #business.update(business_params)
redirect_to #business, notice: 'Business was successfully updated.'
else
render :edit
end
end
def destroy
#business.destroy
redirect_to businesses_url, notice: 'Business was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_business
#business = Business.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def business_params
params.require(:business).permit(:name, :desc, :avatar)
end
end
VIEW THAT CALLS THE BUSINESS
<div class="row">
<div class="col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<%= image_tag current_user.business.avatar.url(:thumb), class:"img-thumbnail" %>
<%= current_user.business.name %>
<%= current_user.business.desc %>
<%= link_to 'create business', new_business_path, class:"pull-right" %>
</div>
</div>
</div>
</div>
Do you have a user_id column in your business table? It would look like this: t.integer "user_id"
Then, to directly associate the business with the user, in businesses_controller.rb I would write the new and create methods in that way:
def new
#business = current_user.businesses.new
end
def create
#business = current_user.businesses.new(business_params)
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render :new
end
end
Hope this helps.

Setting up Rails Controller for the through in has_many through relationship

I am creating a rails web app with a many-to-many through model. The application is to allow users to populate their dashboard with a number of pre-defined "widgets". So I have a table of users (created and managed by devise) and a table of widgets. All good. So to manage the through bit, I have a table of "subscriptons". Here are my models:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :widget
validates_uniqueness_of :user_id, scope: :widget_id
end
class User < ActiveRecord::Base
has_many :subscriptions
has_many :widgets, through: :subscriptions
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Widget < ActiveRecord::Base
has_many :subscriptions
has_many :users, through: :subscriptions
end
However, I don't really understand how to create the subscriptions. I would ideally like the create form to just have a selector to choose from all available widgets and then user the current user:id but I am not sure how this would work, here is my controller:
def new
#subscription = Subscription.new
end
def create
#user = current_user
#subscription = #user.subscriptions.build(subscription_params)
respond_to do |format|
if #subscription.save
format.html { redirect_to #subscription, notice: 'subscription was successfully created.' }
format.json { render :show, status: :created, location: #subscription }
else
format.html { render :new }
format.json { render json: #subscription.errors, status: :unprocessable_entity }
end
end
end
I would really appreciate a nudge in the right direction, as I can't understand how this is done from the official docs and haven't found any good tutorials relating to this.
Assuming you don't have any other attributes on subscriptions you can use the widget_ids= method that your has_many creates on user
Controller
class UserSubscriptionsController
def edit
#user = current_user
end
def update
#user = current_user
if #user.update(user_subscription_params)
redirect_to #user, notice: "Subscriptions updated"
else
render :edit
end
end
private
def user_subscription_params
params.require(:user).permit(widget_ids: [])
end
end
View
<%= form_for #user, url: user_subscription_path, method: :patch do |f| %>
<%= f.collection_check_boxes :widget_ids, Widget.all, :id, :name %>
<%= f.submit %>
<% end %>
The routes in my example would have
resource :user_subscription, only: [:edit, :update]
But obviously you can amend based on what you want your routes to be.
Rails will automatically create the subscriptions when updating the user.
You could instead just use the collection_check_boxes when editing a user normally if you wanted. There is also collection_select
Docs
You can save data like this using subscription form.
= form_for #subscription do |f|
= f.select :widget_id, options_from_collection_for_select(Widget.all, "id", "title"), {}, {:class => "form-control select" }
= f.hidden_field :user_id, :value => current_user.id
#other subscription fields
= f.submit

Strong Parameters : Hash param is missing or the value is empty

I have a form where I have a table with checkboxes in order to select rows and save IDs in my DB.
But it throws me an error:
Param is missing or the value is empty: leadallocation"
I tried different ways but still nor working. So at the moment I just wand to save the hash in my db. Thanks.
# Never trust parameters from the scary internet, only allow the white list through.
def leadallocation_params
params.require(:leadallocation).permit(:campaign_id, :company_id, :user_id)
end
Request Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"company_ids"=>["38",
"40"],
"commit"=>"Create Leadallocation"}
The controller
class LeadallocationsController < ApplicationController
before_action :set_leadallocation, only: [:show, :edit, :update, :destroy]
# GET /leadallocations
# GET /leadallocations.json
def complete
end
def index
#leadallocations = Leadallocation.all
end
# GET /leadallocations/1
# GET /leadallocations/1.json
def show
end
# GET /leadallocations/new
def new
#leadallocation = Leadallocation.new
#comps = Company.all
end
# GET /leadallocations/1/edit
def edit
end
# POST /leadallocations
# POST /leadallocations.json
def create
#leadallocation = Leadallocation.new(leadallocation_params)
#leadallocation.company_id = params[:company_ids]
respond_to do |format|
if #leadallocation.save
format.html { redirect_to #leadallocation, notice: 'Leadallocation was successfully created.' }
format.json { render :show, status: :created, location: #leadallocation }
else
format.html { render :new }
format.json { render json: #leadallocation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /leadallocations/1
# PATCH/PUT /leadallocations/1.json
def update
respond_to do |format|
if #leadallocation.update(leadallocation_params)
format.html { redirect_to #leadallocation, notice: 'Leadallocation was successfully updated.' }
format.json { render :show, status: :ok, location: #leadallocation }
else
format.html { render :edit }
format.json { render json: #leadallocation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /leadallocations/1
# DELETE /leadallocations/1.json
def destroy
#leadallocation.destroy
respond_to do |format|
format.html { redirect_to leadallocations_url, notice: 'Leadallocation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_leadallocation
#leadallocation = Leadallocation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def leadallocation_params
params.require(:leadallocation).permit(:campaign_id, :company_id, :user_id)
end
end
The models
class Leadallocation < ActiveRecord::Base
belongs_to :campaign
belongs_to :company
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_many :activities
belongs_to :campaign
has_many :leadallocations
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Company < ActiveRecord::Base
belongs_to :campaign
has_many :subsidiaries
has_many :leadallocations
end
class Campaign < ActiveRecord::Base
belongs_to :client
has_many :leads
has_many :activities
has_many :contacts
has_many :users
has_many :leadallocations
end
Routes.rb
resources :leadallocations
The view
<h1>New Leadallocation</h1>
<p id="notice"><%= notice %></p>
<h1>Listing Companies</h1>
<%= simple_form_for(#leadallocation) do |f| %>
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Country</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #comps.each do |company| %>
<tr>
<td><%= check_box_tag "company_ids[]", company.id %></td>
<td><%= company.name %></td>
<td><%= company.country %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
<%= link_to 'Back', leadallocations_path %>
The way you are using Strong Params requires that your parameters adhere to a specific form.
In this case, you params need to be nested under the key leadallocation
The problem is in your form, instead of check_box_tag, you will want to do f.check_box and use this documentation to see the available options.
This will nest your attributes under the leadallocation, if it doesn't then something might be wrong with your setup of models and forms.
Basically all this is to say you want to change your params from this:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"company_ids"=>["38",
"40"],
"commit"=>"Create Leadallocation"}
to this:
{"utf8"=>"✓",
"authenticity_token"=>"GruGL758jT4FO+t/BTRGLrD2uCGOj/qUCrB5VswquzR9N7JZ/rouLmGZnTE7A+XTARiLwkOy1n3/zMqhzuenmg==",
"leadallocation" => {
"company_ids"=>["38","40"]
}
"commit"=>"Create Leadallocation"}
The problem is here:
"company_ids"=>["38", "40"]
It should be:
"leadallocation" => {
"company_ids" => ["38", "40"]
}
This is the standard construct for a Rails object to be passed to your db. This is why strong_params is structured the way it is...
params.require(:top_level_param).permit(:child_params)
--
You can get around this by simply using .permit:
#app/controllers/leadallocations_controller.rb
class LeadAllocationsController < ApplicationController
private
def leadallocation_params
params.permit(:company_ids)
end
end
This is not a permanent fix but a HACK!!!
Fix:
#app/views/lead_allocations/new.html.erb
<%= simple_form_for #leadallocations do |f| %>
<%= f.collection_check_boxes :company_ids, Company.all, :id, :name %>
<%= f.submit %>
<% end %>
References here:
Simple Form collection_check_boxes
Rails collection_check_boxes
This should send the data you require back to your controller. Notice the f.___ -- this tells Rails to build a form using the FormBuilder you've invoked around #leadallocations.
Simply, this means that your data will be encapsulated in the {"leadallocations" => ...} params, whereas if you just use check_box_tag, it will assume the data is independent.
Also, never use HTML to stylize your page. The use of <br> and <table> should only be for formatting. CSS is the only way to stylize your application. Your use of <table> seems to be okay; I just wanted to highlight because most people don't get the idea of HTML vs CSS.
Furthermore, there is another problem - with your associations:
class Leadallocation < ActiveRecord::Base
belongs_to :company
end
You cannot assign multiple company ID's to a belongs_to relationship:
I've seen instances where [foreign_key]_ids can be passed, but it's not recommended; indeed, an antipattern.
What you'll be looking for is has_and_belongs_to_many:
#app/models/leadallocation.rb
class LeadAllocation < ActiveRecord::Base
has_and_belongs_to_many :company
end
#app/models/company.rb
class Company < ActiveRecord::Base
has_and_belongs_to_many :leadallocations
end
#join table - companies_leadallocations
This will definitely permit you associate multiple leadallocations per company and vice versa.

Undefined method, avatar and name for nil:NilClass

undefined method avatar?' for nil:NilClass
undefined methodname' for nil:NilClass
Hi, I'm receiving the following errors in my partial. The reason I listed both is because after commenting out the line causing the first error message, I get the second error which leads me to believe the problem isn't with "avatar" or "name" specifically, but with something else,though I don't know what. In rails console, I'm able to call user and name on a comment. I also seeded the database using Faker if that matters. Here's the partial.
<%= content_tag :div, class: 'media', id: "comment-#{comment.id}" do %>
<%= link_to '#', class: 'pull-left' do %>
<%= image_tag(comment.user.avatar.small.url) if comment.user.avatar? %>
<% end %>
<div class="media-body">
<small>
<%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
<% if policy(comment).destroy? %>
| <%= link_to "Delete", [#topic, #post, comment], method: :delete %>
<% end %>
</small>
<p><%= comment.body %></p>
</div>
<% end %>
Also, please see the render.
<div class="col-md-4">
<% if policy(Comment.new).create? %>
<h4>Leave a comment</h4>
<br/>
<%= render partial: 'comments/comment', locals: { topic: #topic, post: #post, comment: #comment } %>
<% end %>
</div>
The below are my user model and comments_controller
class UsersController < ApplicationController
before_filter :authenticate_user!
def update
if current_user.update_attributes(user_params)
flash[:notice] = "User information updated"
redirect_to edit_user_registration_path(current_user)
else
render "devise/registrations/edit"
end
end
private
def user_params
params.require(:user).permit(:name, :avatar)
end
end
Comments_controller
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.find(params[:post_id])
#comments = #post.comments
#comment = current_user.comments.build(comment_params)
#comment.post = #post
#new_comment = Comment.new
authorize #comment
if #comment.save
redirect_to [#topic, #post], notice: "Comment was submitted successfully."
else
flash[:error] = "There was an error submitting the comment. Please try again."
end
end
I've already reset the database, but to no avail. Stuck as to what the issue is. Thanks for your help.
Please see below for my User and Comment models.
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
default_scope { order('created_at DESC') }
validates :body, length: { minimum: 5 }, presence: true
after_create :send_favorite_emails
private
def send_favorite_emails
self.post.favorites.each do |favorite|
if favorite.user_id != self.user_id && favorite.user.email_favorites?
FavoriteMailer.new_comment(favorite.user, self.post, self).deliver
end
end
end
end
User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :posts
has_many :comments
has_many :votes, dependent: :destroy
has_many :favorites, dependent: :destroy
mount_uploader :avatar, AvatarUploader
def role?(base_role)
role == base_role.to_s
end
def favorited(post)
self.favorites.where(post_id: post.id).first
end
def voted(post)
self.votes.where(post_id: post.id).first
end
private
end
If you're getting
undefined method foo for nil:NilClass
it's that the thing you're calling your method on is nil.
So in your case, you're calling avatar? and name on something nil.
Looking at your code, it's clear comment.user is (a) what those methods are called on, and hence (b) what is nil.
Result: your comment has no user. Either enforce all comments (including new/empty/stub ones) to have an user (blank user?), or make your view so that a user is not necessary.
The issue was discovered. In the partial render
comment: #comment
should be
comment: comment

Comment functionality in Rails. undefined method `first_name' for nil:NilClass

One thing I could never do properly is implement a comment feature. I'm not leaving my computer until I learn to do it.
The error is thrown on this line:
<strong><%= comment.user.first_name %></strong>
Apparently user is nil; but why? And what do I have to do to get this to work?
A comment should belong to a guide and a user. Users and guides both have many comments.
I started with
rails g scaffold comment body:text guide:references user:references
and then migrated the database. I completed the model associations as well.
Here is my guides controller show action:
def show
#guide = Guide.find(params[:id])
#comment = #guide.comments.build
end
Here is the part of the Guide show view that deals with comments:
<h3>Comments</h3>
<% #guide.comments.each do |comment| %>
<div>
<strong><%= comment.user.first_name %></strong>
<br />
<p><%= comment.body %></p>
</div>
<% end %>
<%= render 'comments/form' %>
Here is the comment form partial:
<%= simple_form_for(#comment) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :body %>
<%= f.association :user %>
<%= f.association :guide %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
User.rb
class User < ActiveRecord::Base
# 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 :email, presence: true
validates :email, uniqueness: true
validates :runescape_username, presence: true
has_many :guides
has_many :comments
acts_as_voter
def user_score
self.guides.inject(0) { |sum, guide| sum += guide.score }
end
end
Comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :guide
end
Comments controller create action:
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Replace the line
#comment = Comment.new(comment_params)
with
#comment = current_user.comments.build(comment_params)
in your Comments#create action.
You get this error because you don't assign current_user to created Comment. That's why comment.user returns nil.
As stated by AndreDurao, you can also validate user_id presence in Comment model, like this:
class Comment
validates_presence_of :user
# ...
end
for getting rid of that error try this <%= comment.user.try(:first_name) %>

Resources