Problems in Rails undefined method `map' for #<Contact:0x000000013aa76b48> - ruby-on-rails

I'm putting together a combo box or called the same as a select in rails, I put everything together but it gives me an error that tells me that I have a problem with the map inside the select, I'm using simple_form_for and I'm doing a map inside the collection inside the selector or called in simple_for associatio.
I copy the view and the controller
This view
<h1>HistContact#index</h1>
<p>Find me in app/views/hist_contact/index.html.erb</p>
<%= simple_form_for #histcontact, url:hist_contact_index_path do |f| %>
<% f.association :contact, collection: #contacts.map{|cont| [cont.name , cont.id]}%>
<%f.submit "buscar"%>
<% end %>
<table id = "client_table" class="table table-striped table-sm">
<thead>
<tr>
<th>Id</th>
<th>fecha</th
</tr>
</thead>
<tbody>
<% #histcontacts.each do |c|%>
<tr>
<td> <%= c.id %> </td>
<td> <%= c.created_at %></td>
</tr>
<% end %>
</tbody>
</table>
the controller
class HistContactController < ApplicationController
before_action :authenticate_user!
def index
#histcontacts = HistContact.all
#contacts = Contact.all
end
def new
#histcontact = HistContact.new
#contacts = Contact.new
end
def create
#histcontact = HistContact.find(contact_id: params[:contact])
end
private
def contactID(current_user)
client_id = Client.where(user_id: current_user.id)
contact_id = Contact.where(client_id: client_id.ids[0])
return contact_id
end
end
Thank you

According to error, you are trying to map a single object instead of an array of objects. Based on your controller code, the view file you shared is probably new.html.erb. To solve this problem you need do it like this:
def new
#histcontact = HistContact.new
#contacts = Contact.all
end

Related

Rails 7 paginate without sending API request

In my Rails 7 app I want to display transactions inside data table. because I expect there will be hundreds of them, I'm using pagy gem to paginate the result. Table data comes from client API request. As a response I get an array of hashes from which I extract data.
Here is my code:
Controller where I've made a request:
# transactions_controller.rb
class TransactionsController < ApplicationController
def index
response = client.transactions.list(platform_id: current_user.platform_id, page: 1, per_page: 100)
#transactions = response.body['data']
end
private
def client
#client ||= TestAPI::Client.new
end
end
Corresponding view:
#views/transactions/index.html.erb
<table class="table table-striped">
<thead>
<tr>
<b>
<tr>
<th>Date</th>
<th>Amount</th>
</tr>
</b>
</tr>
</thead>
<tbody>
<% #transactions.map do |transaction| %>
<tr>
<td>
<%= transaction['created_at'] %>
</td>
<td>
<%= transaction['amount_cents'] %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%== pagy_bootstrap_nav(#pagy) %>
The pagination works well how to set it up without reloading the page? now when I use binding.pry in the controller to check if the request to the API was made, like below:
def index
response = client.transactions.list(platform_id: current_user.platform_id, page: 1, per_page: 100)
binding.pry
(...)
With each transition between pagination pages, a request is sent to the external API. How to send a request just once and operate on a single response?
[EDIT]
Controller with Low-Level Caching:
class TransactionsController < ApplicationController
def index
#pagy, #transactions = pagy_array(cashed_transactions.body['data'], items: 8)
end
private
def cashed_transactions
Rails.cache.fetch("merchants/#{current_user.platform_merchant_id}/transactions", expires_in: 12.hours) do
client.transactions.list(platform_merchant_id: current_user.platform_merchant_id, page: 1, per_page: 100)
end
end
end
Client API to get list of transactions:
def list(platform_merchant_id:, page: nil, per_page: nil, status: nil, platform_payment_id: nil)
filters = { 'filters[status]': status, 'filters[platform_payment_id]': platform_payment_id }.compact
params = { filters:, page:, per_page: }.compact
get("merchants/#{platform_merchant_id}/transactions", params:)
end

undefined method `each' for nil:NilClass on an erb array iteration

Im currently working in an Rails 5 application where you can search for a first name or last name and records of the customers of that account would be displayed. However I am getting a Nil object return from search algorithm.
customers_controller:
class CustomersController < ApplicationController
def index
if params[:keywords].present?
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order)
else
#customers = []
end
end
end
As you can see if there is no records found is suppose to return an empty array but is returning a Nil object.
customers/index.html.erb
[![<header>
<h1 class="h2">Customer Search</h1>
</header>
<section class="search-form">
<%= form_for :customers, method: :get do |f| %>
<div class="input-group input-group-lg">
<%= label_tag :keywords, nil, class: "sr-only" %>
<%= text_field_tag :keywords, nil,
placeholder: "First Name, Last Name or Email Address",
class: "form-control input-lg" %>
<span class="input-group-btn">
<%= submit_tag "Find Customers", class: "btn btn-primary btn-lg" %>
</span>
</div>
<% end %>
</section>
<section class="search-results">
<header>
<h1 class="h3">Results</h1>
</header>
<table class="table table-striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Joined</th>
</tr>
</thead>
<tbody>
<% #customers.each do |customer| %>
<tr>
<td><%= customer.first_name %></td>
<td><%= customer.last_name %></td>
<td><%= customer.email %></td>
<td><%= l customer.created_at.to_date %></td>
</tr>
<% end %>
</tbody>
</table>
</section>][1]][1]
The first thing you should understand is that instance variables return nil if they haven't been set. If you say #fake_var == nil it will be true if you never defined #fake_var before this. You can contrast this with regular local variables, which will raise a NoMethodError if you try and use them before they're defined. For example, puts(fake_var) will raise a NoMethodError for fake_var.
Now look at your template. No matter what it will loop over #customers. If #customers has not been set, you'll see a NoMethodError because you can't call each on nil.
Finally, look at your controller action:
def index
if params[:keywords].present?
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order)
else
#customers = []
end
end
Specifically the case when params[:keywords].present?. You never set #customers in this case so it will be nil when the template tries to access it.
I think if you simply replaced #customer = with #customers = it would solve your problem.
you can force it to return array using #to_a which converts nil to empty array
def index
return [] unless params[:keywords]
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order
).to_a
end
https://apidock.com/ruby/Array/to_a

Cannot go to show action nested resources

student_classes_controller.rb
class StudentClassesController < ApplicationController
before_filter :set_batch
def index
#sections = StudentClass.all
end
def show
#section = StudentClass.find(params[:id])
end
private
def set_batch
#batch = Batch.find(params[:batch_id])
end
end
in the view of student_classes/index.html.erb
<table class="table table-bordered table-hover">
<thead bgcolor="#B7B7B7">
<th>Section</th>
<th>Number of Students</th>
<th>Details</th>
</thead>
<% #sections.each do |section| %>
<tr>
<td><%= section.name %></td>
<td><%= section.students.count %></td>
<td><%= link_to 'View Details', batch_student_classes_path(#batch , section) %></td>
</tr>
<% end %>
</table>
the url of view details is this http://localhost:3000/batches/1/student_classes.1
but i want to make it as this http://localhost:3000/batches/1/student_classes/1
routes.rb
resources :batches do
resources :student_classes
end
rake routes
batch_student_classes GET /batches/:batch_id/student_classes(.:format) student_classes#index
POST /batches/:batch_id/student_classes(.:format) student_classes#create
new_batch_student_class GET /batches/:batch_id/student_classes/new(.:format) student_classes#new
edit_batch_student_class GET /batches/:batch_id/student_classes/:id/edit(.:format) student_classes#edit
batch_student_class GET /batches/:batch_id/student_classes/:id(.:format) student_classes#show
PUT /batches/:batch_id/student_classes/:id(.:format) student_classes#update
DELETE /batches/:batch_id/student_classes/:id(.:format) student_classes#destroy
The path method you want to call is batch_student_class_path not batch_student_class*es*_path.

update_attributes is not working

Here's my controller
class ActivitiesController < ApplicationController
def exercises
if current_user.userprofile.present? #chef whether there is a userprofile object
#weeknum = current_user.userprofile.week
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
end #end check userprofile
end
def updatexercises
respond_to do | format |
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
#dayly_activity.update_attributes(params[:#dayly_activity])
#dayly_activity.save
format.html { render action: "exercises" }
end
end
end
And my template
<h1>WEEKLY EXERCICES</h1>
Day : <%= #dayly_activity.day %>
<%= form_for(#dayly_activity, :url => { :action => "updatexercises" }) do | f | %>
<table>
<tr>
<td>Jogging:</td>
<td>
<% list = (0..20).to_a %>
<%= f.select :jog, list %>
x 0.1 km
</td>
</tr>
<tr>
<td>Bicycling:</td>
<td>
<% list = (0..10).to_a %>
<%= f.select :bicycl, list %>
km
</td>
</tr>
<tr>
<td>Push ups:</td>
<td>
<% list = (0..20).to_a %>
<%= f.select :pushups, list %>
x 10 times
</td>
</tr>
<tr>
<td colspan = "2"><%= f.submit %></td>
</tr>
</table>
<% end %>
When I click the button, the Daily+activity object is not being saved. Am I missing some thing
EDIT
I've tried to hard code this way and it saving to the database.
#dayly_activity.jog = 17
#dayly_activity.pushups = 13
#dayly_activity.save
Obviously, the problem must be with the update_attributes
You need to use params[:dayly_activity] (drop the # sign).
Also, I would put these two lines :
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
#dayly_activity.update_attributes(params[:dayly_activity])
Outside of your respond_to block (put them on top of it).
You can also drop the #dayly_activity.save, update_attributes do it automatically and will returns true/false if it works/fails.
You have error in [:#dayly_activity]
And in that code
#dayly_activity.update_attributes(params[:#dayly_activity])
#dayly_activity.save
save is useless. update_attributes saving the record.
It better to check result of update_attributes. So you can catch validation errors.
For example
if #dayly_activity.update_attributes(params[:dayly_activity])
redirect_to dayli_activity_path, :notice => "Updated"
else
render :edit
end

Generating a table in Ruby on Rails

Why doesn't this produce a table when called from my view? With fields_table(#user, ["id", "username"]) I am not getting the tbody's trs or tds, but I am getting everything else.
def fields_table(obj, fields)
return false if obj.nil?
content_tag(:table) do
thead = content_tag(:thead) do
content_tag(:tr) do
content_tag(:td, "Property") + content_tag(:td, "Value")
end
end
tbody = content_tag(:tbody) do
fields.each do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end
end
thead + tbody
end
end
This code just iterates through the fields. It doesn't return anything, so the enclosing tbody isn't going to have anything to content.
tbody = content_tag(:tbody) do
fields.each do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end
end
You need to return something like you do in the other parts of the code or change it to something like this:
tbody = content_tag(:tbody) do
fields.map do |name|
content_tag(:tr) do
content_tag(:td, name) + content_tag(:td, obj.read_attribute(name))
end
end.join
end
I would recommend rendering a partial using the collection argument, and built in rails goodness to do this type of operation. Im guessing you want the table headings to line up with the fields? You can still do that with something along the lines of the following (havent tested, but should work),
In your model define a class method or array as constant containing the attributes you want to display on the front end, e.g.
models/user.rb
VisibleFields = [:id, :username]
#workaround for toplevel class constant warning you may get
def self.visible_fields
User::VisibleFields
end
views/users/index.html.erb
<table>
<thead>
<tr>
<% User.visible_fields.each do |field| %>
<th><%= field.to_s.titleize %></th>
<% end %>
</tr>
</thead>
<tbody>
<%= render :partial => 'user', :collection => #users %>
</tbody>
</table>
**views/users/_user.html.erb**
<tr>
<% user.visible_fields.each do |field| %>
<td class="label"><%= field.to_s.titleize %></td><td class="value"><%= user.send(:field) %></td>
<% end %>
</tr>

Resources