Rails - when a row returns nil - ruby-on-rails

I'm getting this error when loading my view that has a Model User that has no records in it. I simply want it to return "Unassigned" in the view if there is no record. Otherwise, display the first and last name of the User. Displaying User first and last name works as expected when a record exists.
I've messed around with many different combinations of this and can't see to get it to work.
Error:
undefined method `full_name' for nil:NilClass
In tickets.index.html.erb:
<% #tickets.each do |ticket| %>
<%= ticket.user.full_name %>
<% end %>
In ticket.rb Model
def full_name
if full_name.blank?
full_name = "Unassigned"
else
ticket.user.first_name + ' ' + ticket.user.last_name
end
end

The problem is that when you call ticket.user that might be nil, so you can't call anything on it. You have the right idea in making a method on your Ticket model to isolate this, but it's calling itself which will get an infinite loop, and also you're still calling the method on your user and not your ticket. Try this:
In your view:
<% #tickets.each do |ticket| %>
<%= ticket.full_name %>
<% end %>
In your ticket model:
def full_name
if user.nil?
return "Unassigned"
else
return user.full_name
end
end
And in your user model:
def full_name
return "#{first_name} #{last_name}"
end
I made the user model have its own method for this so it's further isolated (following OO practices).

Related

Rails: How to pass params of multiple checkbox to the model

i built this form that generate me some chebox with value like "U6", "U8" eccc
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |category| %>
<%= check_box_tag 'categories_selected[]', category -%>
<% end %>
Now i have to pass the value of selected check_box to a method in my model.
Now is:
def create_tournament_team_categories
TeamCategory::NAMES.each do |name|
team_category = TeamCategory.where(name: name).first_or_create
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
I would like to replace the TeamCategory::NAMES.each do with "selected check_box each do" and TeamCategory.where(name: name) with the value selected.
Thank you in advance
I am a newbie with Rails. What I see is that you took the part of the form to create the team, right?
For your code straight forward it could be:
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |name| %> #you are looping through team category NAMES constant
<%= check_box_tag 'category_names_selected[]', name %>
<% end %>
Your form as is allows more than one category to be selected.
For the method:
def create_tournament_team_categories(category_names_selected)
category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
you will probably use this method in your teams_controller.rb. In the controller, you should be able to retrieve from params a freshly created array of selected names with something along the lines with this.
#category_names_selected = params[:category_names_selected]
I do not know how complicated your app is so it might also be nested under ["team"][:category_names_selected] or ["team"]["category_names_selected"] in your params hash.
To see the exact structure of the params hash and adjust the equation above you can add for example require 'pry' at the top of your controller file and then but the binding.pry just after the part where your method is executed. When you restart the server and the app hits this part of the controller you should be able to see the exact structure of your params hash in the terminal.
You can then pass the array to the method that you can call in the controller. Do not forget to add :category_names_selected to the strong params in the controller. I hope this helps.
Controller on line 30
def create
#tournament = Tournament.new(tournament_params)
#tournament.sport_club = current_user.sport_club
#category_names_selected = params[:category_names_selected]
if #tournament.save
redirect_to tournaments_path, notice: 'Torneo creato con successo'
end
end
Method create_tournament_team_categories in the model
after_create :create_tournament_team_categories
def create_tournament_team_categories(category_names_selected)
#category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end

Rails helper method return NilClass

I have this code in User#index view:
<%= User.find_each do |user| %>
<%= user.name %>
<% end %>
which returns the user names:
user1 user2 user3 ...
Then I move this code to the UserHelper:
module UserHelper
def get_users
User.find_each do |user|
user.name
end
end
end
And call it from the User#index view with:
<%= get_users %>
The problem is that this is not returning any user. If I use <%= get_users.class %> it outputs NilClass. Why is the helper method not returning the user names?
Your helper method implicitly returns the result of calling find_each, which is different than returning a collection of user names.
Think of it like running 5.times { |n| puts n }: what's the value of that? Not "0 1 2 3 4", but "5", because times returns what it was called on, not what's run in its block.
Your original code, by the way, returns the exact same thing--you are relying on a side effect inside the find_each block, i.e., appending user.name to the response.
If you want to return a collection of the users' names you'd want to map/etc. and grab each user's name. Or, IIRC, you can do a find and a pluck so you only get back the users' names instead of all user fields.
You can use as below also,
<%= User.all.map(&:name).join(' ') %>

In Ransack update ranackers dynamically when a model gets updated

I have Company Customer and CompanyCustomerField models. Customers store the hstore values in a column "properties" - the keys are from the CompanyCustomerField#name field. When a new CompanyCustomerField get created i need to add the #name to ransack to make them searchable.
When a new CompanyCustomerField gets added and I go to the search form I get
undefined method `*_cont' for #<Ransack::Search:0x00007ff670100978>
because the new field is not available for searching. If i shutdown my fails server and reboot it works because it gets it into ransack.
I don't know how to dynamically add the functionality into ransack. Any ideas greatly appreciated.
Customer.rb. this puts all the searchable fields into ransack but doesnt update it when new ones get added. because this only gets called once.
class Customer < ApplicationRecord
# ['favorite_color', 'receive_email_marketing' etc etc]
CompanyCustomerField.pluck(:name).each do |name|
ransacker name.to_sym do |parent|
Arel::Nodes::InfixOperation.new('->', parent.table[:properties], Arel::Nodes.build_quoted(name))
end
end
end
here is the search form:
#customers/index.html
<%= search_form_for #search, remote: true do |f| %>
<% current_company.customer_fields.each do |field| %>
<%= render "customers/search_fields/#{field.field_type}", f: f, field: field %>
<% end %>
<% end %>
#customers/search_fields/text_field
<%= f.label (field.name + "_cont").to_sym, field.name.humanize %>
<%= f.text_field (field.name + "_cont").to_sym %>
....
Even if moving reloading to controller, still same result.
CustomersController.rb
def index
Customer.reload_ransacker
#search = current_company.customers.includes(:owner).ransack(params[:q])
#customers = #search.result.page(params[:page])
end
Customer.rb
def self.reload_ransacker
puts "==="
puts "reload ransacker"
puts "==="
CompanyCustomerField.pluck(:name).each do |name|
ransacker name.to_sym do |parent|
Arel::Nodes::InfixOperation.new('->', parent.table[:properties], Arel::Nodes.build_quoted(name))
end
end
end
ActionView::Template::Error (undefined method `foo_cont' for #<Ransack::Search:0x00007fba3c05d5b8>):
SOLUTION:
needed to override:
module Ransack
module Adapters
module ActiveRecord
module Base
def ransacker(name, opts = {}, &block)
#ransackable_attributes = nil
self._ransackers = _ransackers.merge name.to_s => Ransacker
.new(self, name, opts, &block)
end
end
end
end
end
#ransackable_attributes needs to be reset to nil so in def ransackable_attributes(auth_object = nil) the instance var is nil and can reload
should be considered a bug in ransack.

Find previous or next array

I created a rails app that allows the user to read a magazine.
To do so, I created two scaffolds, one for the magazine and an other for the pages inside of it. I then made a one-to-many relationship, so the pages belong to the magazine.
Each page is an image, since they are digitized then uploaded in a multi-upload form.
Recently, the group I work for asked me to find a way to allow the user to read two pages at the same time, so I made some tweaks, and it works like a charm.
However, I now have a problem: I want to set some "previous" and "next" links, but I can't find a way to do so
Here is what I have done so far:
magazine_controller.rb
def create
#magazine = Magazine.new(magazine_params)
if #magazine.save
#index = 0
(params[:images] || []).each_with_index do |image, index|
if index.even?
#This way, #index increments every other upload
#So I'm sure I have two images with the same page_number
#index += 1
end
#magazine.pages.create(image: image, page_number: #index)
end
redirect_to #magazine, notice: 'Magazine créé'
else
render :new
end
end
models/page.rb
class Page < ApplicationRecord
belongs_to :magazine
validates_presence_of :magazine
mount_uploader :image, PageUploader
def previous
self.class.first.where('page_number < ?', page_number).limit(1).first
end
def next
self.class.first.where('page_number > ?', page_number).limit(1).last
end
end
views/pages/show.html.erb
<% #page.each do |p| %>
<%= image_tag p.image %>
<%= p.inspect %>
<% end %>
<br />
<%= #page.first.page_number %>
<%= link_to '< Précédent', magazine_page_path(magazine_id: #magazine.slug, id: #page.previous) if #page.previous %>
<%= link_to 'Suivant >', magazine_page_path(magazine_id: #magazine.slug, id: #page.next) if #page.next %>
<br />
<%= link_to 'Back', magazines_path %>
page_controller.rb
private
def set_page
#magazine = Magazine.find_by(slug: params[:magazine_id])
#was 'find_by' before I was asked to show two records at the same time
#page = #magazine.pages.where(page_number: params[:id])
end
So with this code, I'm getting the error undefined method 'previous' for #<Page::ActiveRecord_AssociationRelation:0x007ff4f702ad48>. I don't have a clue about how to find if there is a following "page" or not.
Any idea welcome!
Thank you in advance
Remember that #page is no longer a single record, it's an association with two records.
You can create previous and next page methods in Page class for the association instead of the object (self.previous instead of previous). It will get a new association for the previous (or next) page number. Note the addiitional code to make sure you're getting the same magazine (which you don't have in your current code that worked for single pages).
Also note that if the association has no records (count == 0) the methods return nil... this is to accommodate your if #page.previous test for no previous (and if #page.next if no next)
def self.previous
new_page_set = Page.where(page_number: (first.page_number - 1), magazine: first.magazine)
return new_page_set.count == 0 ? nil : page_set
end
def self.next
new_page_set = Page.where(page_numberL (first.page_number + 1), magazine: first.magazine)
return new_page_set.count == 0 ? nil : page_set
end

Undefined method each Ruby

The run down. A person can have many bids, this particular person only has one bid.
In my index action I have #bids = Bid.find_by_person_id(params[:person_id])
in my view I do
<% #bids.each do |bid| %>
<%= bid.bid_amount %>
<% end %>
I am getting NoMethodError: undefined method each' for #<Bid:0x007f988a346f00> when visting the index view for person bids.
Is this because this person only has one bid? I feel thats not the case, but other than that im at a loss..
find_by returns the first item. I think you are looking for
Bid.where(person_id: params[:person_id])
Austio's answer is correct.
However, why are you calling the Bid model directly?...
A person can have many bids
You're obviously constructing data from the person model, so why not call the following:
#person = Person.find params[:person_id]
#bids = #person.bids #-> bids belong to #person
This will build the collection without calling where.
Of course, your method only uses a single db query. But even still, the above is much more intuitive.
--
As an aside, you'll also want to use a conditional before your loop:
<% if #bids.any? %>
<% #bids.each.... %>
<% end %>
Having one bid is fine, but having none will cause the loop to spit out an error. The above resolves that issue.

Resources