update_attributes is not working - ruby-on-rails

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

Related

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

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

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

Ruby on Rails how to use submit button with radio buttons

For my final project I need to create two radio buttons with a submit button that will display my GPA for all my classes and those in my major. I can have them displayed easily but am stuck when I need to use radio buttons to display only one
<h2>Please select which GPA you would like to view:</h2>
<%= form_tag("/trans/transcript", :method => "get") do %>
<table>
<tr>
<th>Major Credits</th>
<th>All Credits</th>
</tr>
<tr>
<td><%= radio_button_tag(:gpa, "Major") %></td>
<td><%= radio_button_tag(:gpa, "All") %> </td>
</tr>
</table>
<%= submit_tag("View GPA") %>
<% end %>
<p> Major credits GPA <%= #transcript.GPA_for_major %>
<p> All credits GPA <%= #transcript.GPA_for_non_major %>
Everything appears fine but I'm not sure how to set up the controller to say if he clicks the major gpa radio button and clicks "View GPA" this <%= #transcript.GPA_for_major %> should display
SHORT ANSWER
Make an instance variable #gpa in TransController's transcript action
In the transcript action, check for params[:gpa]
set #gpa & #transcript to nil if params[:gpa].nil?
set #gpa to params[:gpa] and #transcript accordingly if params[:gpa] is not nil
In the view/trans/transcript.html.erb
If #gpa is nil, display nothing
If #gpa == "Major" show #transcript.GPA_for_major
If #gpa == "All" show #transcript.GPA_for_non_major
LONG ANSWER
Assuming that the controller is trans and the action is transcript, here is what you should do in TransController
class TransController < ApplicationController
def transcript
if params[:gpa].nil?
#transcript = #gpa = nil
else
#gpa = params[:gpa]
#transcript = ... # Find your transcript here
end
end
# ... other actions
# ... other actions
# ... other actions
end
and here is how the trans/transcript.html.erb view should look like -
<h2>Please select which GPA you would like to view:</h2>
<%= form_tag('trans/transcript', :method => "get") do %>
<table>
<tr>
<th>Major Credits</th>
<th>All Credits</th>
</tr>
<tr>
<td>Major<%= radio_button_tag(:gpa, "Major") %></td>
<td>All<%= radio_button_tag(:gpa, "All") %> </td>
</tr>
</table>
<%= submit_tag("View GPA") %>
<% end %>
<% if #gpa == "Major" %>
<%= #transcript.GPA_for_major %>
<% elsif #gpa == "All" %>
<%= #transcript.GPA_for_major %>
<% end %>

Submit multiple entries to database, from an array, in Rails on the same page

I'm trying to submit multiple entries into the database from an array. So, I create multiple new entries and store them in an array. In the view, I have a form of checkboxes for the user to check which ones he/she wants to add to the database. Upon clicking submit, I would like to add each of these forms to the database all in on shot. Here is the code:
Controller:
class EventsBoysController < ApplicationController
def new
#season = find_season
#meet = find_meet(#season)
#athletes_boys = current_coach.athletes.where(boy: true)
#events_boys = []
#athletes_boys.each do |athlete|
#events_boys << #meet.events_boys.new(:athlete_id => athlete.id)
end
#events = ["400 IH", "100", "1600", "400", "110 HH", "800", "3200", "200"]
end
def create
debugger
#season = find_season
#meet = find_meet(#season)
#events_boys = #meet.events_boys.create(events_boy_permit)
# debugger
if #events_boys.save
redirect_to #events_boys, notice: 'Season was successfully created.'
else
render action: "new"
end
end
private
def find_season
Season.find(params[:season_id])
end
def find_meet season
season.meets.find(params[:meet_id])
end
def events_boy_permit
params.require(:events_boy).permit(:season_id, :meet_id, :athlete_id, :boys_400_m_im, :boys_1600_m, :boys_400_m, :boys_110_m_hh, :boys_800_m, :boys_3200_m, :boys_200_m, :boys_100_m, :time_400_m_im, :time_1600_m, :time_400_m, :time_110_m_hh, :time_800_m, :time_3200_m, :time_200_m, :time_100_m, :place_400_m_im, :place_1600_m, :place_400_m, :place_110_m_hh, :place_800_m, :place_3200_m, :place_200_m, :place_100_m)
end
end
View:
<h1><%= "Create new events for the boys for #{#meet.name}" %></h1>
<table id="events-table">
<tr>
<th></th>
<% #events.each do |event| %>
<th><%= event %></th>
<% end %>
</tr>
<% #events_boys.each do |event| %>
<tr>
<td><%= Athlete.find_by_id(event.athlete_id).name %></td>
<%= form_for [#season, #meet, event], :html => { :mulitpart => true } do |f| %>
<td><%= f.check_box :boys_400_m_im %></td>
<td><%= f.check_box :boys_100_m %></td>
<td><%= f.check_box :boys_1600_m %></td>
<td><%= f.check_box :boys_400_m %></td>
<td><%= f.check_box :boys_110_m_hh %></td>
<td><%= f.check_box :boys_800_m %></td>
<td><%= f.check_box :boys_3200_m %></td>
<td><%= f.check_box :boys_200_m %></td>
<td><%= f.submit "Submit", :class => 'btn' %></td>
<% end %>
</tr>
<% end %>
</table>
<script type="text/javascript">
var athletes = new Array();
var arrayInAthletes = new Array();
element = document.getElementById("events-table");
var athletesArray = element.children[0].children
for (i=1; i < athletesArray.length; i++) {
var rowArray = athletesArray[i].children;
arrayInAthletes = [];
arrayInAthletes[0] = rowArray[0].innerText;
var sum = 0;
for (j=1; j < rowArray.length; j++) {
var checkBox = rowArray[j].children[0];
var checkedValue = $('#'+checkBox.id+':checked').val();
if (checkedValue === "1") {
arrayInAthletes[sum+1] = rowArray[j].children[0].id;
sum += 1;
}
}
athletes[i-1] = arrayInAthletes;
}
</script>
I think what you are looking for is something like the code below (needs to be adapted to your example).
Contact.create([
{first_name: 'Ryan', last_name: 'Smith', email: 'ryan#smith.com'},
{first_name: 'John', last_name: 'Doe', email: 'john#doe.com'}
])
All you need to do is put your data into an array of hashes. Each hash is an object you want to save. This will do a batch insert, which is what I think you want.
You will need to pull the values for checked/unchecked from your params since that is where they are passed to your controller. Cycle through that hash and perform your logic on that.

Rails Average multiple columns

I need to find the average of multiple columns based on a params search across several tables in my VPC controller, but i'm having trouble displaying the average results in the view and also the search is very slow to read from the database. Wondering the best method to do below would be. Would it be best to do the averages in the model? (not sure how this is done though)
Models
class Vpc < ActiveRecord::Base
has_many :results
end
class Result < ActiveRecord::Base
attr_accessible :trial_id, :variety_id, :year, :lint, :turnout, :length_decimal, :length_imperial, :strength, :uniformity, :micronaire, :manual_class
belongs_to :trial, :primary_key => 'trial_id'
belongs_to :variety, :primary_key => 'variety_id'
belongs_to :vpc
has_many :sites, :through => :trial
has_many :growers, :through => :trial
has_many :regions, :through => :sites
end
Controller
class VpcController < ApplicationController
add_breadcrumb "Home", :root_url
add_breadcrumb "Variety Performance Comparison", :vpc_index_path
def index
all = Result.select(:variety_id)
#variety = Variety.where(:variety_id => all).order('variety_name DESC')
#years = Result.select('DISTINCT year')
#regions = Region.all
#irrigations = Trial.select('DISTINCT irrigated').order('irrigated ASC')
end
def search
if params[:variety_one] != params[:variety_two]
#comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
#vone = #comparison.where('variety_id = ?', params[:variety_one]).select('avg(lint) AS lintone')
#vtwo = #comparison.where('variety_id = ?', params[:variety_two]).select('avg(lint) as linttwo')
#count = #comparison.count('DISTINCT results.trial_id')
#years = #comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
#region = #comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
else
redirect_to vpc_index_url, notice: "Can't compare the same variety"
end
#variety_one = Variety.where('variety_id = ?', params[:variety_one]).group('variety_name')
#variety_two = Variety.where('variety_id = ?', params[:variety_two]).group('variety_name')
add_breadcrumb "Results"
end
end
View Results
<h2>VPC</h2>
<p>We found <%= #count.count %> trials that matched your options, spanning <%= #years.length %> years (<%= #years.map{|y| y.year}.join(", ") %>) and <%= #region.length %> regions (<%= #region.map{|r| r.trial.site.region.name}.join(", ") %>).</p>
<table class="table">
<th></th>
<% #variety_one.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<% #variety_two.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<th>Difference</th>
<tr>
<td>Yield (bales/ha)</td>
<td><%= "%.2f" % (#vone.lintone/227) unless #vone.blank? %></td>
<td><%= "%.2f" % (#vtwo.lintwo/227) unless #vtwo.blank? %></td>
<td><%= "%.2f" % ((#vone.lintone/227) - (#vtwo.lintwo/227)) unless #lintone.blank? %></td>
</tr>
</tr>
</table>
<hr>
<div class="accordion" id="accordion2">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseOne">
<b>Overview of results</b> <span class="pull-right"><i class="icon-chevron-down"></i></span>
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
<table class="table">
<th>Year</th>
<th>Site</th>
<th>Region</th>
<th>Grower</th>
<% #comparison.each do |v| %>
<tr>
<td><%= link_to v.trial.year, trial_trials_path(trial_id: v.trial_id) %></td>
<td><%= link_to v.trial.site.site_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.site.region.name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.grower.full_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.grower.blank? %></td>
</tr>
<% end %>
</table>
</div>
</div>
</div>
SQL Error
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id ' at line 1: SELECT COUNT(avg(lint) AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id AS trials_trial_id FROM `results` INNER JOIN `trials` ON `trials`.`trial_id` = `results`.`trial_id` INNER JOIN `trials` `trials_results_join` ON `trials_results_join`.`trial_id` = `results`.`trial_id` INNER JOIN `sites` ON `sites`.`site_id` = `trials_results_join`.`site_id` INNER JOIN `regions` ON `regions`.`region_id` = `sites`.`region_id` WHERE `results`.`variety_id` IN (2300, 2255) AND `trials`.`irrigated` IN (0, 1, 2) AND `results`.`year` IN (2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013) AND `sites`.`region_id` IN (1, 2, 3, 4, 5, 6, 7, 8) AND (variety_id = '2300') GROUP BY trials.trial_id HAVING COUNT(*) = 2
Looking at your massive controller, I would suggest the following:
#comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
#count = #comparison.count('DISTINCT results.trial_id')
#years = #comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
#region = #comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
Keep that chunk the same but create a migration to add indexes to increase the performance.
You should not call average so many times but instead do a select on the values you want
#vone = #comparison.where('variety_id = ?', params[:variety_one]).select(avg(lint) as lint, avg...
#vtwo = #comparison.where('variety_id = ?', params[:variety_two]).select(avg(lint) as lint, avg...)
Now in your views you can just get the needed attributes.
After that, have a look at the logs to see if there are any N+1 you can reduce.

Resources