undefined method 'each for nil:NilClass - ruby-on-rails

I am working on a system that is currently in use and an error for a feature that is not very often used has come up.
NoMethodError in Offer_receipts#index
Showing /Users....../app/views/offer_receipts/index.html.erb where line #8 raised:
undefined method `each' for nil:NilClass
Extracted source (around line #8):
5: <th>Patron</th>
6: <th>One Time Offer</th>
7: </tr>
8: <% for offer_receipt in #offer_receipts %>
9: <tr>
10: <td><p> popld</p></td>
11: <td><%= offer_receipt.patron_id %></td>
This error happens when this partial render page is currently being displayed:
<h2>Offers</h2>
<div id="offers">
<% if #offers.count > 0 %>
< % #offers.each do |o| %>
<%= show_one_time_offer(o, #patron) %>
<% end %>
<% else %>
<strong>There are no offers currently available</strong>
<% end %>
</div>
Once the one time offer is clicked on, this page is loaded and this is the page the error happens on:
index.html.erb
<% title "Offer Receipts" %>
<table>
<tr>
<th>Patron</th>
<th>One Time Offer</th>
</tr>
<% for offer_receipt in #offer_receipts %>
<tr>
<td><%= offer_receipt.patron_id %></td>
<td><%= offer_receipt.one_time_offer_id %></td>
<td><%= link_to "Show", offer_receipt %></td>
<td><%= link_to "Edit", edit_offer_receipt_path(offer_receipt) %></td>
<td><%= link_to "Destroy", offer_receipt, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<p><%= link_to "New Offer Receipt", new_offer_receipt_path %></p>
and here are two other files that define the methods and scope of the One Time Offer receipt
offer_receipt.rb
class OfferReceipt < ActiveRecord::Base
belongs_to :patron
belongs_to :one_time_offer
validates :patron, :presence=>true
validates :one_time_offer, :presence=>true
require 'offer_receipt_validator.rb'
validates_with OfferReceiptValidator
end
offer_receipts_controller.rb
class OfferReceiptsController < ApplicationController
def create
begin
#patron = Patron.find(params[:patron])
rescue ActiveRecord::RecordNotFound
flash[:error] = "You must provide a patron for an offer receipt"
redirect_to root_url
return
end
#offer_receipt = OfferReceipt.new(:patron_id=>params[:patron], :one_time_offer_id=>params[:one_time_offer])
if #offer_receipt.save && #patron
redirect_to #patron, :notice => "Recorded offer receipt"
else
flash[:error] = "There was a problem saving your offer receipt"
redirect_to #patron
end
end
end
There are other index.html.erb files for listing other things with the exact same for each loop, and they are working fine. I also checked the database and there are over 2000 rows so that can't be the issue.

Your instance variable, #offer_receipt is not set in your #index controller action.
You should add the #index action. Something like this should work:
class OfferReceiptsController < ApplicationController
def index
#offer_receipts = OfferReceipt.all
end
end
You can also add additional logic in the #index action. You might want to scope the instance variable to a current_user, for example.
#offer_receipts = OfferReceipt.where(:user_id => current_user.id)

Related

How to use Rails 5.2 form_with to trigger a specific action?

My application needs to duplicate a Skill (from skills index) as many times the user needs it in his cart. So I decided to trigger the add-to-cart method of the skills_controller when the related form, including the number of duplicates and the Skill's id, is submitted. For this purpose, I added counter to the strong parameters of skills_controller.
Unfortunately, I am missing something to correctly setup the form: when submitted, it triggers the create method. Here is the code:
routes.rb extract
resources :skills, :path => "variables" do
resources :values_lists
member do
post :add_to_cart
get :create_values_list
get :upload_values_list
get :remove_values_list
end
collection do
get :index_all
end
end
skills_controller.rb method
def add_to_cart
#template_skill = Skill.find(params[:id])
iterations = params[:skill][:counter].to_i
until iterations == 0
#skill = #template_skill.deep_clone include: [:translations, :values_lists]
#skill.business_object_id = session[:cart_id]
#skill.template_skill_id = #template_skill.id
#skill.code = "#{#template_skill.code}-#{Time.now.strftime("%Y%m%d:%H%M%S")}-#{iterations}"
#skill.is_template = false
#skill.save
iterations -= 1
end
#business_object = BusinessObject.find(session[:cart_id])
redirect_to #business_object, notice: t('SkillAdded2BO') # 'Skill successfully added to business object'
end
index.html.erb table content
<tbody>
<% #skills.each do |skill| %>
<tr data-href="<%= url_for skill %>">
<% if not session[:cart_id].nil? %>
<td>
<%= form_with model: #skill, :action => "add_to_cart", :method => :post, remote: false do |f| %>
<%= f.text_field :counter, value: "1", class: "mat-input-element", autofocus: true %>
<button type="submit" class="mat-icon-button mat-button-base mat-primary add-button" title="<%= t('AddToUsed') %>">
<span class="fa fa-plus"></span>
</button>
<% end %>
</td>
<% end %>
<td class="no-wrap"><%= skill.code %></td>
<td><%= link_to skill.translated_name, skill %></td>
<td><%= link_to translation_for(skill.parent.name_translations), skill.parent %></td>
<td><%= skill.responsible.name %></td>
<td><%= skill.updated_by %></td>
<td class="text-right"><%= format_date(skill.updated_at) %></td>
</tr>
<% end %>
</tbody>
Thanks a lot for your help!
According to this form helpers guide, the syntax you used doesn't exist
form_with model: #model, action: :custom_action
So in this case, you have to specify the url parameter for form_with to make it works.
<%= form_with model: #skill, url: :add_to_cart_skill_path(#skill), method: :post, remote: false do |f| %>

creating a button to update a database entry in ruby

I have created a database of ideas with a votes field. I want users to be able to press a button to increase the vote count of an idea and then refresh the screen. I have created a method called increment_vote, but cannot seem to find how to save the new vote value in my database. This is my part of my index.html.erb code:
<% #ideas.each do |idea| %>
<tr>
<td><%= idea.content %></td>
<td><%= increment_vote(idea) %></td>
<td><%= link_to 'Vote', ideas_path(:mode => "Vote"), :class => "button", :method => :get %></td>
</tr>
If I call the increment vote method from the link to vote code, I get an "undefined method `to_model' for true:TrueClass. Did you mean to_yaml" error.
This is my method code in the ideas.controller:
helper_method :increment_vote
def increment_vote(idea)
idea.votes +=1
idea.save
end
This is currently causing the error, but it is increasing the vote of the first idea in the table.
Can anyone please help?
You can't call increment_vote method from view, you need to create controller action for it and call it when the user clicks the link
# views/ideas/index.html.erb
<% #ideas.each do |idea| %>
<tr>
<td><%= idea.content %></td>
<td><%= link_to 'Vote', upvote_idea_path(idea), class: "button", method: :post %></td>
</tr>
<% end %>
# routes.rb
resources :ideas do
post :upvote, on: :member
end
# ideas_controller.rb
def upvote
Idea.find(params[:id]).upvote
redirect_to :index
end
# models/idea.rb
def upvote
update(votes: votes + 1)
end

Render partial in new site, rails

Ok so far i created an new controller with:
rails g controller home settings
In the settings.html.erb i want to display an partial so that i simply added one line:
<%= render "categories/index", :locals => {:categories => #categories} %>
So my categories/_index.html.erb looks like this, and worked:
<% for category in #categories do %>
<tr>
<td><%= category.typ %></td>
<td><%= link_to "Löschen", category,:class => 'btn btn-mini btn-danger', method: :delete, data: { confirm: 'Sind sie sicher?' } %></td>
</tr>
<% end %>
<tr>
<%= form_for Category.new do |f| %>
<td> <%= f.text_field :typ, :class => "input-small" %></td>
<td><%= f.submit "Speichern", :class => 'btn btn-mini btn-success' %></td>
</tr>
<% end %>
</table>
</div>
But now when i open localhost:3000/home/settings i get the error:
NoMethodError in Home#settings
Showing C:/Sites/rublesql/app/views/categories/_index.html.erb where line #10 raised:
undefined method `each' for nil:NilClass
Extracted source (around line #10):
7: <th></th>
8: </tr>
9:
10: <% for category in #categories do %>
11: <tr>
12: <td><%= category.typ %></td>
So my question is what did i wrong?
Categories controller:
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def destroy
#category = Category.find(params[:id])
#category.destroy
redirect_to categories_path
end
def create
#category = Category.new(params[:category])
#category.save
redirect_to categories_path
end
end
It means the #categories instance variable hasn't been set.
Check in your controller that it sets #categories = xx.
Three things I notice:
You're mixing notations with the partial. Previously you would do, render partial: "x", locals: {}, now you can drop the partial key and just send the view path in, but if you choose to do this you also remove the locals: key:
<%= render "categories/index", {categories: #categories} %>
Also:
{:categories => #categories} will make categories your local, not #categories.
However, your instanced #categories should pass through as well, so it isn't your issue.
Finally:
#categories isn't set (or if it is, it becomes nil). Either make sure your controller correctly assigns it, or otherwise check .nil? or for .present? before attempting to loop through them.

My controller is -persistently- sending wrong params[:id] in Rails?!

I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand

Why am I receiving a routing error when the controller method exists, the route is defined and the view calls it?

I have a simple shopping cart application that displays the session's shopping cart with line_items in it on the sidebar of the application layout. I am attempting to add a button at the end of each line item (rendered in _line_item.html.erb) that decrements the quantity in the cart by one using remote: true and some JS. However, when I load the page (before I click anything) I am receiving this routing error from Rails 3.1 in development with no special gems or configurations installed:
Routing Error
No route matches {:action=>"decrement", :controller=>"line_items"}
Here is my method in controllers/line_items_controller.rb, which has been working well for me until now:
def decrement
#line_item = LineItem.find(params[:id])
#line_item.quantity -= 1
if #line_item.quantity.empty?
#line_item.destroy
end
respond_to do |format|
format.js {#current_item = #line_item}
end
end
Here is the entry in routes.rb:
resources :line_items do
member do
post 'decrement'
end
end
Here is the code in the partial _line_item.html.erb, which works fine without the button_to link:
<% if line_item == #current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
<td><%= button_to 'Remove one', line_item, decrement_line_item_path, remote: true %></td>
</tr>
I must be missing something but I cannot find it. It seems everything is in order to me. What am I doing wrong? Thanks very much.
Edit: here is the error I receive when I use decrement_line_item_path(line_item):
ArgumentError in Store#index
Showing /Users/Michael/Sites/rails/depot/app/views/line_items/_line_item.html.erb where line #9 raised:
wrong number of arguments (4 for 3)
Extracted source (around line #9):
6: <td><%= line_item.quantity %>×</td>
7: <td><%= line_item.product.title %></td>
8: <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
9: <td><%= button_to 'Remove one', line_item, decrement_line_item_path(line_item), remote: true %></td>
10: </tr>
decrement_line_item_path expects an argument for the individual item and you're not giving it one.
Try:
<%= button_to 'Remove one', decrement_line_item_path(line_item), remote: true %>

Resources