I'm receiving an undefined method `site_name' for nil:NilClass error for the following. Would appreciate any help. I'm trying to list the site_name in the Site table and i'm not sure how best to resolve the issue.
class Site < ActiveRecord::Base
attr_accessible :site_id, :site_name, :region
has_many :trials, :foreign_key => "site_id"
end
class Trial < ActiveRecord::Base
attr_accessible :trial_id, :site_id, :year, :trial_type
scope :year, ->(year) { where(year: year) }
scope :trial_id, ->(trial_id) { where(trial_id: trial_id) }
belongs_to :site
end
My Controller:
class TrialsController < ApplicationController
def index
#years = Trial.group('year').order('year DESC')
end
def trial
#trial = Trial.trial_id(params[:trial_id])
end
**def list
#list = Trial.year(params[:year]).order(:region_id).joins(:sites).where('sites.site_id' => :site_id)
end**
end
My view:
<% #list.each do |list| %>
<tr>
<td>
<%= link_to list.site.site_name, trial_trials_path(trial_id: list.trial_id) %>
</td>
<td>
<%= link_to list.trial_type, trial_trials_path(trial_id: list.trial_id) unless list.trial_type.blank? %>
</td>
<td>
<%= link_to list.trial_type, trial_trials_path(trial_id: list.trial_id) %>
</td>
<td>
<%= link_to list.planted_at, trial_trials_path(trial_id: list.trial_id) unless list.planted_at.blank? %>
</td>
<td>
<%= link_to list.picked_at, trial_trials_path(trial_id: list.trial_id) unless list.picked_at.blank? %>
</td>
</tr>
<% end %>
What if you just change the line to this:
<%= link_to list.site.site_name, trial_trials_path(trial_id: list.trial_id) if list.site.try(:site_name) %>
Also, you could do a Site.where(site_name: nil) in the Rails console to see which site doesn't have a name.
if you don't want page crush even if there is not site for list, you could try to use this
list.site.try(:site_name)
but I think that you should use another flow, like
Do not let to create list without site.
Do not list lists without sites.
You have to decide about your default site name, eg. "Example.com". And then you simply define it on nil:
def nil.site_name
"Example.com"
end
And the error will go away.
Related
I have a rails application which is not routing as I expected. The search method in the controller is rending show. I've cut down the code to the minimal components and I am posting them here as suggested.
Rails.application.routes.draw do
resources :backups
get 'backups/search' => 'backups#search'
resources :components
resources :backup_media
end
class Component < ActiveRecord::Base
has_many :backups
has_many :backup_media, :through => :backups
end
class BackupMedium < ActiveRecord::Base
has_many :backups
has_many :components, :through => :backups
end
class Backup < ActiveRecord::Base
belongs_to :component
belongs_to :backup_medium
# value to match either the name of the component or backup_medium
def self.search(value)
tables = "backups, components, backup_media"
joins = "backups.backup_medium_id = backup_media.id and components.id = backups.component_id"
c = find_by_sql "select * from #{tables} where components.name like '%#{value}%' and #{joins}"
b = find_by_sql "select * from #{tables} where backup_media.name like '%#{value}%' and #{joins}"
c.count > 0 ? c : b
end
end
class BackupsController < ApplicationController
def search
#backups = Backup.search(params[:search])
render 'index'
end
def index
#backups = Backup.all
end
def show
# this would normally be the code to show an individual backup
# but I'm re-using the code from index because the routing is broken
#backups = Backup.all
end
end
views/backups/_search.html.erb
<%= form_tag backups_search_path, :method => 'get' do %>
<%= label_tag(:search, "Search for:") %>
<%= text_field_tag :search, params[:search], {:placeholder => 'Component or Media' }%>
<%= submit_tag "Search", :name => nil %>
<% end %>
views/backups/index.html.erb
<h1>Listing Backups</h1>
<p id="notice"><%= notice %></p>
<%= render :partial => 'search' %>
<table>
<tr>
<th>id</th>
<th>component_id</th>
<th>backup_medium_id</th>
</tr>
<% #backups.each do |backup| %>
<tr>
<td><%= backup.id %></td>
<td><%= backup.component.name %></td>
<td><%= backup.backup_medium.name %></td>
</tr>
<% end %>
</table>
views/backups/show.html.erb is copied from index.html.erb since it is incorrectly receiving the search results
<h1>Show Backup</h1>
<p id="notice"><%= notice %></p>
<%= render :partial => 'search' %>
<table>
<tr>
<th>id</th>
<th>component_id</th>
<th>backup_medium_id</th>
</tr>
<% #backups.each do |backup| %>
<tr>
<td><%= backup.id %></td>
<td><%= backup.component.name %></td>
<td><%= backup.backup_medium.name %></td>
</tr>
<% end %>
</table>
Suggestions on improving the search method will be welcomed.
As mentioned above, after the search is executed, the show.html.erb is rendered instead of search.html.erb
For a working demo (with better code thanks to suggestions here) see
https://github.com/pamh09/rails-search-demo
You do not have a backups_search_path in your routes, therefore it is treating search in the query string as an id and thus rendering show.html.erb, so try
get 'backups/search' => 'backups#search', as: :backups_search
In debugging I found that rails consistently routed to the wrong view when it was unhappy with the return object coming from the model.
For example, I have two models:
class Task < ApplicationRecord
has_many :task_details
end
class TaskDetail < ApplicationRecord
belong_to :task
end
I want to display a table, each row in table is one TaskDetail and allow user input. After that user submits, all data will put to server. Here is my code:
(Note that: I #data[:task] is a task object because I want to return a hash with some information for view)
<%= form_for #data[:task], :url => tasks_path do |f| %>
<table> ... </table>
<% end %>
My question is: How can I do as my requirement.
thanks
Ensure that your Task model has accepts_nested_attributes_for :task_details and then you can do something like...
<%= form_for #data[:task], :url => tasks_path do |f| %>
<table>
<tr>
<th>Task Name</th>
<th>Task Description</th>
<tr>
<%= f.fields_for :task_details do |task_detail| %>
<tr>
<%= task_detail.hidden_field :id %>
<td><%= task_detail.text_field :name %></td>
<td><%= task_detail.text_field :description %> </td>
<tr>
<% end %>
</table>
<% end %>
Note the use of the hidden field for :id ... you need that so that rails can distinguish data from existing tasks versus a new task you're entering.
In your new method you should ensure there's at least one new task detail to provide an empty line on the form to input the detail
def new
...
#data[:task].task_details.build
...
end
when I replace the nil values manually with data, I get no errors.
<% #visits.each do |f| %>
<tr>
<td><%=f.owner.car_number unless f.owner.car_number.nil?%></td>
<td><%=f.owner.car_type unless f.owner.car_type.nil?%></td>
<td><%=f.owner.car_year unless f.owner.car_year.nil?%></td>
<td><%=f.owner.first_name unless f.owner.first_name.nil?%> <%=f.owner.last_name unless f.owner.last_name.nil?%></td>
<td><%=f.owner.phone unless f.owner.phone.nil?%></td>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
</tr>
Better you need to add validation to stop entry of nil on owner in visit or the model where the association has defined to owner with visit
here I am consider here visit model has one owner
class Visit < ActiveRecord::Base
has_one :owner
validates :owner, presence: true
end
Or another solution using try
<% #visits.each do |f| %>
<tr>
<% ["car_number", "car_type","car_year", "first_name", "last_name", "phone"].each do |meth| %>
<td><%= f.try(:owner).send(meth) %></td>
<% end %>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
</tr>
<% end %>
I am assuming #visits contains valid list of objects.
Now, lets read the error carefully:
undefined method `car_number' for nil:NilClass
Where are you applying car_number? Hint: to object f.owner. Meaning f.owner is nil , so f.owner.car_number.nil will still throw an error.
Tweak them to:
<%= f.owner.car_number if f.owner %>
Or better:
<% #visits.each do |f| %>
<tr>
<% if f.owner %>
<td><%=f.owner.car_number %></td>
<td><%=f.owner.car_type %></td>
<td><%=f.owner.car_year %></td>
<td><%=f.owner.first_name %> <%=f.owner.last_name %></td>
<td><%=f.owner.phone %></td>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
<% end %>
</tr>
Check the first iteration.
Instead of :
unless f.owner.car_number.nil?
Use..
unless f.owner.nil?
Or you can check first before iterating, like:
<% unless #visits.nil? %>
<% #visits.each do |f| %>
....
<% end %>
<% end %>
I would like to be able to search orders by id or by order status.
My current code is working but not 100%.
There is a has_many relationship between the Order and the Order Status models.
The order status model has four entries:
1.Processing , 2.Completed, 3.Cancelled, 4.Refunded
Example:
I have a simple form to enter the order id and another form with a select tag
with all the Order Statuses to search by order status.
If I search for order id 1, I get all the orders with a number 1 in the id and I also get all the orders with order status 1.
I would like get a result of either order id or order status.
Order model
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(search)
where("cast(id as text) LIKE ? OR order_status_id LIKE ? ", "%#{search}%", "%#{search}%")
end
end
Order Status model
class OrderStatus < ActiveRecord::Base
has_many :orders
end
Orders Controller
def index
#order_statuses = OrderStatus.all
if params[:search]
#orders = Order.search(params[:search])
else
#orders = Order.all
end
end
Order index view
<div class="row">
<div class="col-sm-6 form-group">
<%= form_tag orders_path, :method => 'get', class:"" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil, class:"btn btn-primary" %>
</p>
<% end %>
</div>
<div class="col-sm-6 form-group">
<%= form_tag orders_path, :method => 'get', class:"" do %>
<p>
<%= select_tag :search, options_from_collection_for_select(OrderStatus.all, :id, :name, params[:search]) %>
<%= submit_tag "Search", :name => nil, class:"btn btn-primary" %>
</p>
<% end %>
</div>
</div>
<table class="table">
<tr>
<th>Order Id</th>
<th>amount</th>
<th>status</th>
<th>Last Updated</th>
<th>manage</th>
</tr>
<% #orders.each do |order| %>
<tr>
<td><%= order.id %></td>
<td><%= order.total %></td>
<td><%= order.order_status.name %></td>
<td><%= order.updated_at %></td>
<td><%= link_to 'details', order %> |
<%= link_to 'edit', edit_order_path(order) %> |
<%= link_to 'delete', order_path(order), method: :delete, data: { confirm: 'Are you sure?' } %>
</td>
</tr>
<% end %>
<tr><td colspan="4"></td></tr>
</table>
I've researched the following links but I'm not finding or understanding a solution.
Links:
http://railscasts.com/episodes/37-simple-search-form?autoplay=true
http://railscasts.com/episodes/111-advanced-search-form-revised?autoplay=true
http://guides.rubyonrails.org/active_record_querying.html
Rails Search Form
Build static dropdown menu for simple search Rails 3
You can do a search by either order_id or order_status :name attribute with the following
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(query)
query.to_s.is_i? ? where(id: query) : joins(:order_status).where('order_statuses.name LIKE ?', "%#{query}%")
end
end
In order to use the is_i? method you will need to extend the String class by creating an initializer file to require a new String extension file
# config/initializers/core_extensions.rb
Dir[File.join(Rails.root, "lib", "core_extensions", "*.rb")].each {|f| require f }
and then create your new String extension file and is_i? method
# lib/core_extensions/string.rb
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
credit this SO answer for the is_i? method
There's no need to cast the id into text and then using like to match it. This should be enough to get what you need.
class Order < ActiveRecord::Base
belongs_to :order_status
def self.search(search)
where("id = ? OR order_status_id LIKE ? ", search, "%#{search}%")
end
end
I'm a rails noob trying to develop a simple exercise log app, and I'm up against my limits. A user selects a category, and a specific workout, and I return a list of exercises belonging to that workout.
An effort is a user specific instance of an exercise.
class Exercise < ActiveRecord::Base
has_many :efforts
end
class Effort < ActiveRecord::Base
belongs_to :exercise
end
I'm retrieving the list of exercises in the efforts controller
class EffortsController < ApplicationController
def log_workout
#exercises = Exercise.where("category_id = ? AND workout_id = ?", params[:exercise][:category_id], params[:exercise][:workout_id])
#effort = Effort.new
end
end
My problem is that I'm not sure about my approach up to this stage. It does work so I have attempted to enable the user to log their workout by using a form like the following but I'm (not surprisingly) not getting the right info back from it and I'm not sure where to go with it...
<%= form_tag save_workout_path, method: :put do %>
<table>
<tr>
<th>Exercise</th>
<th>Sets</th>
<th>Reps</th>
</tr>
<%= #exercises.each do |exercise| %>
<%= fields_for "efforts[]", #effort do |f| %>
<tr>
<td><%= exercise.name %></td>
<td><%= f.number_field :sets %></td>
<td><%= f.number_field :reps %></td>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag "Log it" %>
<% end %>
If anybody has any thoughts/guidance/solutions I'd appreciate it