Conditionally calling 'collection_select' from a model/helper with AJAX - ruby-on-rails

I'm looping through each instance of a built sub-tournament - and the problem that I'm having has to do with conditionally creating a collection_select box with data fetched via ajax. Here's the view - the line I want to insert code in is marked:
View
<% #tournament.sub_tournaments.each_with_index do |sub, i| %>
<%= f.fields_for :sub_tournaments, sub, :validate => false do |sub_form| %>
<div class="tab-content standings-row-<%= i %>" style="display:none">
<table>
<thead>
<tr>
<th> <h4>Standing</h4> </th>
<th class="standings-field-<%= i %>"></th>
<th></th>
</tr>
</thead>
<tbody>
<%= sub_form.fields_for :standings, :validate => false do |standings| %>
<tr>
<td>
<%= f.hidden_field :_destroy %><%= f.text_field :standing, :class => "standing", readonly: true, :type => "" %>
</td>
<td class="standings-ajax-<%= i %>">**INSERT HERE**</td>
<td><span class="remove">Remove</span></td>
</tr>
<% end %>
</tbody>
</table>
<div class="add-item">
<%= link_to_add_standings_fields(sub_form, :standings) %>
</div>
</div>
<% end %>
<% end %>
I thought about doing the conditional check (it depends upon whether the game selected is a team game or a single-player game) in the controller, but it seems to make more sense as a method (or a helper?). At the moment I have it in Standing.rb (below) - but I'm getting a no method "collection_select" error - so probably form helpers aren't available in models, which seems reasonable. So how could I do this?
Standing.rb
def team_or_player(game)
if Game::TEAM_GAMES.include?(game.name)
self.collection_select(:team_division_id, TeamDivision.where("game_id = ?", game.id),
:id, :name, {include_blank: true})
else
self.collection_select(:player_id, Player.where("game_id = ?", game.id),
:id, :handle, {include_blank: true})
end
end
And how can I pass the f to my AJAX call?
AJAX
$(".standings-ajax-<%= #tab_number %>").html("<%= ** ?? **.team_or_player(#standing, #game) %>");

You can call helper in model:
ActionController::Base.helpers.collection_select( ... )
So from what I can see you should change team_or_player() to class method and call it with:
Standings.team_or_player(#standing, #game)
or as instance
#standing.team_or_player(#standing, #game)
But that you should use self instead of passing #standing.
Me preference would be to put that logic directly in view or to helper.

Related

Error when trying to link to patient profile

I'm getting an error when trying to link_to a patient profile when a provider views his patients list. I have no problem displaying all the names of the patients that belong to the provider but when trying to link to the patient profile I get an undefined method 'id'.
So the way it works is, patients can search for providers and add them to the List model. On the provider side, I just list out all the patients that added that specific provider. Here is my erb code below,
<div class="body">
<div class="body">
<% if #active_patients.count > 0 %>
<table>
<thead>
<tr>
<th>Patient Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div class="no-records">
<%= image_tag "icon-no-records", class: "image" %>
<div class="text">You have no patients.</div>
</div><!--no-records-->
<% end %>
</div><!--body-->
</div>
Here is my List model,
class List < ApplicationRecord
belongs_to :membershipable, :polymorphic => true
belongs_to :provider
def patient
membershipable_type=='Patient' ? membershipable : nil
end
def provider_user
patient.try(:user)
end
end
Also here's the error message ->
Let Rails do the work of building the path. Each ActiveRecord model has a to_param method which decides how the instance will be encoded in an URL. By default it returns the model id but it could also be a slug based on the title or another property of the model.
Calling your helper like patient_path(patient) should do the trick.
Additionally, in your current code, you're referring to the previously unused #patient variable, even though it looks like you want to refer to list.patient instead.
Here:
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
you have the variable list available to you. It appears that you get the patient by doing list.patient, as you do here:
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
But, then you try to use a variable called #patient, here:
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> .
when you don't have the variable #patient. So, you get your nil error.
Instead, it seems you should do:
<%= link_to patient_path(id: list.patient.id), class: "btn" do %>View<% end %> .
Or, as milgner points out, you could simply do:
<%= link_to patient_path(list.patient), class: "btn" do %>View<% end %> .
Also, you might want to look into the Law of Demeter, which you violate (IMO) when you do:
list.patient.role.user.first_name

rails 5 form_tag with original DB value and after new selection in form, both records must be updated

I have a form_tag with a radio_button_tag and it populates with data from DB. It must simply be directed to a customised update action(update_multiple) where a boolean column is updated for all those 2 records which have been changed in the form.
For e.g. say when initially the form was populated from DB with record 1's radio button selected and now user changed his selection to record 3, then at Submit of form tag the update of both records must occur but the problem is the code at submit, only collects id of record which is now selected in that group.How do I get id of that record also which was unselected so that I can update_all for both of them at one go?
And if Submit cannot handle this action, then is there a way in controller or form to persist the id of the initial selected record before populating the form? As you see, I've tried with collecting an array of ids[] with radio_button_tag.
TIA for your help.
Here's the form code:
<%= form_tag update_multiple_user_cv_attachments_path, method: :put, action: :update_multiple do %>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th> Select a CV </th>
<th> Resume Name </th>
</tr>
</thead>
<tbody>
<% #cv_attachments.each do |cv_attachment| %>
<%= hidden_field_tag cv_attachment.main, :value => params[:main] %>
<tr>
<td><%= radio_button_tag "cv_attachment_ids[]", cv_attachment.id, cv_attachment.main %> </td>
<td><%= cv_attachment.attachment.file.basename %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= submit_tag "Select Main", :class =>'button' %>
<% end %>
Here's the controller update_multiple code.
def update_multiple
CvAttachment.update_all(["updated_at=?", Time.now], :id => params[:cv_attachment_ids])
end
I can think of 2 ways to achieve your objective.
update the boolean for all the attachments which belong to the user to false and then update the one which has been selected to true
include a hidden field in the form and set it to the id that is already true. Then in the controller action, update the one that is selected to true and the one in the hidden field to false. This is probably a better option and you'll probably want to wrap the d/b updates in a transaction.
<tbody>
<% #cv_attachments.each do |cv_attachment| %>
<% if cv_attachment.main %>
<%= hidden_field_tag "ex_main_cv", cv_attachment.id %>
<% end %>
<tr>
<td><%= radio_button_tag "main_cv", cv_attachment.id, cv_attachment.main %> </td>
<td><%= cv_attachment.attachment.file.basename %></td>
</tr>
<% end %>
</tbody>
controller
def update_main_attachment // probably a better name for this method
if params["ex_main_cv"] != params["main_cv"]
Attachment.transaction do
deselected_attachment = Attachment.find(params["ex_main_cv"]
deselected_attachment.update_attribute(:main, false)
selected_attachment = Attachment.find(params["main_cv"]
selected_attachment.update_attribute(:main, true)
end
end
end
Many thanks #margo. Here' how I resolved it partly your way of using hidden_field. But for now keeping this thread open as I'm making 2 DB updates for toggle of same column.
<tbody>
<% #cv_attachments.each do |cv_attachment| %>
<% if cv_attachment.main %>
<%= hidden_field_tag "ex_main", cv_attachment.id %>
<% end %>
<tr>
<td><%= radio_button_tag "new_main", cv_attachment.id, cv_attachment.main, :id => "#{cv_attachment.id}"%> </td>
<td><%= cv_attachment.attachment.file.basename %></td>
</tr>
<% end %>
</tbody>
and in controller:
def update_main
if request.put?
if params["ex_main"] != params["new_main"]
CvAttachment.find(params[:ex_main]).toggle!(:main)
CvAttachment.find(params[:new_main]).toggle!(:main)
end
end

Dynamic checkbox with Ajax in Rails

I have a Form with some checkboxes loaded from the Database, and an option to add other items manually to the items table. This is done by Ajax in the code below...
item_controller.rb
def manual_item_add
#manual_item = Item.find(params[:id_item].to_i)
respond_to do |format|
format.js
end
end
manual_item_add.js.erb
$("#items_table").append("<%= escape_javascript(render 'manual_item_add', :manual_item => #manual_item) %>")
_manual_item_add.html.erb
...
<td><%= check_box_tag("manual_items[]", item.id, true) %></td>
...
edit_items.html.erb
<%= form_tag( {controller:"item", action:"edit_items"}) do %>
<p align="center">
<%= select_date(#account.start_date, prefix: 'start_date') %>
to
<%= select_date(#account.end_date, prefix: 'end_date') %>
</p>
<%= hidden_field_tag 'id_account', #account.id %>
<table id="items_table" class="subtable" align="center" width="55%">
....
<tr>
<th colspan="6">Items added manually</th>
</tr>
<tr>
<th># ID</th>
<th>Type</th>
<th>Description</th>
<th>Ammount</th>
<th>Date</th>
<th>Include in the account</th>
</tr>
</table>
<p align="center"><%= submit_tag("Save", class: "btn") %></p>
<% end %>
<%= form_tag( {controller:"item", action:"manual_item_add"}, method:"get", remote: true) do %>
<h4 align="center">Add item manually</h4>
<p align="center">Item ID:
<%= text_field_tag "item_id", nil , size:5, maxlength:5 %>
<%= submit_tag("Add Item", class: "light_btn") %>
</p>
<% end %>
So... the problem here is that though I see the new checkboxes i am adding to the table (they are being created normally), the "manual_items[]" array is not being passed to the controller when I submit the resulting form (by the way, the "items_table" is inside the form definition).
Does anybody know what I am doing wrong? Sorry for the newbie question, I'm starting to work with Ruby + Rails.
Unfortunately, I don't have a definitive answer for this problem. The only working solution I've tried was to use JQuery to force parameters to be part of the form:
$(document).ready(function() {
$("#edit_items_form").submit(function(event) {
$(this).append($("input[name='manual_items[]']:checked"));
$(this).submit();
});
});
I am definitely not comfortable to this solution, I'd like to know why these Ajax checkboxes are not automatically recognized as being part the form.

Should I save a Model calculation as an attribute?

I have an app that enables a user to create a new room using a form to enter name, description, length, and width. Each room created becomes a new record and the app calculates the 'size' of the room as 'length' * 'width'. This is a simple app that I'm playing with to learn Rails but I may take it further to have a collection of rooms form a house, with some total 'size' of each house.
My question relates to the 'size' value and how that should be integrated into the app. I initially thought that the user should see the value of 'size' right away on the form, but shelved that once it appeared that Ajax may be required. I moved the 'size' method calculation from the view to the model to conform to "fat model, skinny controller" concept and I now show the 'size' in the 'index' view, leaving the 'new' view purely for entering data.
I initially set up the model to include length, width and size. See migration for the Room model:
20150118183743_create_rooms.rb
class CreateRooms < ActiveRecord::Migration
def change
create_table :rooms do |t|
t.string :name
t.text :description
t.integer :length
t.integer :width
t.integer :size
t.timestamps null: false
end
end
end
Should I save 'size' for each record to the database? I've read that it shouldn't be necessary to save calculations as an attribute to the model. Presumably, the app should handle that? What's the correct way to think about this?
My 'index' view calculates & returns max 'length' and 'width', but I run into an error when I try to calculate the max 'size'. I have a calculation (i.e., method) for this in model but it appears to be wrong. Any suggestions?
Below are relevant code:
room.rb
class Room < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 30 },
uniqueness: { case_sensitive: false }
validates :length, :width, presence: true,
numericality: { only_integer: true,
less_than_or_equal_to: 1000,
greater_than_or_equal_to: 1 }
def size
size = length * width
end
def max_room
size.max
end
end
rooms_controller.rb
class RoomsController < ApplicationController
def show
#room = Room.find(params[:id])
end
def new
#room = Room.new
end
def index
#rooms = Room.all
end
def create
#room = Room.new(user_params)
if #room.save #a boolean, if able to save the instance
flash[:success] = "You created a new Room!!"
redirect_to #room #we send the user to the room
else
render 'new' #so we want to render the new template
end
end
private
def user_params
params.require(:room).permit(:name, :description, :length,
:width, :size)
end
end
index.html.erb
<% provide(:title, 'All Rooms') %>
<h1>All rooms</h1>
<div class="container">
<div class="row column-md-7">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-right">Length (ft.) </th>
<th class="text-right">Width (ft.) </th>
<th class="text-right">Size (sq.ft.) </th>
<th class="text-center">Delete? </th>
</tr>
</thead>
<tbody>
<% #rooms.each do |room| %>
<tr>
<td> <%= link_to room.name, room %> </td>
<td> <%= room.description %> </td>
<td class="text-right"> <%= room.length %> </td>
<td class="text-right"> <%= room.width %> </td>
<td class="text-right"> <%= room.size %> </td>
<td class="text-center"> <%= link_to "delete", room, method: :delete,
data: { confirm: "You sure?" } %> </td>
</tr>
<% end %>
</tbody>
</table>
<div class="alert alert-info">
The model contains <%= pluralize(Room.count, "room") %> in total.
The max length is <%= Room.maximum('length') %>.
The max width is <%= Room.maximum('width') %>.
</div>
</div>
</div>
I tried showing 'size' by adding
The max size is <%= Room.max_room %>
but that returned an error.
new.html.erb
<% provide(:title, "New Room") %>
<h1>The Rooms page </h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#room) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.label :length, "Length (ft.)" %>
<%= f.number_field :length %>
<%= f.label :width, "Width (ft.)" %>
<%= f.number_field :width %>
<%= f.submit "Create my room", class: "btn btn-primary" %>
<% end %>
</div>
</div>
show.html.erb
<% provide(:title, #room.name) %>
<h1>The "<%= #room.name %>" page </h1>
<h2>This page contains the show action associated with the
Rooms page </h2>
<br>
<br>
<div class="container">
<div class="col-md-6 col-md-offset-3">
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-right">Length (ft.) </th>
<th class="text-right">Width (ft.) </th>
<th class="text-right">Size (sq.ft.) </th>
</tr>
</thead>
<tbody>
<tr>
<td> <%= #room.name %> </td>
<td> <%= #room.description %> </td>
<td class="text-right"> <%= #room.length %> </td>
<td class="text-right"> <%= #room.width %> </td>
<td class="text-right"> <%= #room.size %> </td>
</tr>
</tbody>
</table>
</div>
</div>
<hr>
<%= link_to "Create a new room", new_room_path, class: "btn btn btn-primary" %>
routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get 'home' => 'static_pages#home'
get 'calculations' => 'static_pages#calculations'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'new_room' => 'rooms#new'
get 'rooms' => 'rooms#index'
resources :rooms
end
I plan to use apps that will be heavy with numerical calculations so I want to get these fundamentals right. I don't want the app's database to blow up if I'm saving too many calculations down when they should be done (perhaps) in a virtual environment.
So, to recap ....
Should a app calculation be saved to the database as an attribute to a new record?
What might be the correct calculation/method for 'size'?
If I want to perform a calculation on a calculated value, does that value first have to be saved as an attribute?
Your implementation of max_room is wrong, since the size value is just a number, the max method is not defined on a number, but instead it should be called on an Enumerable of values.
So Room should be implemented this way:
class Room < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 30 },
uniqueness: { case_sensitive: false }
validates :length, :width, presence: true,
numericality: { only_integer: true,
less_than_or_equal_to: 1000,
greater_than_or_equal_to: 1 }
def size
size = length * width
end
class << self
# This is a class method, since it depends on all the rooms
# not on a specific room
def max_size
# This will delegate the calculation to the database
select('MAX(length * width) AS max')[0]['max'];
end
# But, this will instantiate the records on memory before it makes the calculation
# def max_room
# all.max{ |room| room.length * room.width }
# end
# This is a class method as well
def max_room
order('size DESC').first
end
end
end
Should a app calculation be saved to the database as an attribute to a new record?
If the attributes on which the calculated value depends will change frequently, in this case you should not save the calculated value, but rather calculate it every time you need it. But as I can see the length and the width of a room will not change, so the calculated value will need to be calculated once, and saved to be used when needed (e.g to calculate the max_size), so in this case you need to create an attribute size and calulate it when you create the record using a hook.
before_save :calculate_size
private
def calculate_size
size = length * width
end

How to Handle 2 tables with one form_tag? Rails 3

Beneficiaries
id (PK)
name
age
income
Beneficiary_loans
id (PK)
beneficiary_id (FK)
amount
rate
period
What I'm doing is, selecting a list of beneficiary from [Beneficiaries] table and displaying as follows
<%= form_tag({:action => 'update_survey_list_status', :status=>4}) do %>
<table width="100%">
<tr>
<th>Beneficiary Details</th>
<th>Amount</th>
<th>Rate</th>
<th>Period</th><th>
<input type='checkbox' name='checkall' onclick='checkedAll();'>
</th>
</tr>
<% #publishedlist.each do |b| %>
<tr>
<td><%= b.firstname %></td>
<%= fields_for :beneficiaryloan do |bloan| %>
<td> <%= bloan.text_field :amount%></td>
<td> <%= bloan.text_field :rate%></td>
<td> <%= bloan.text_field :period%></td>
<% end %>
<td><%= check_box_tag "benificiary_ids[]",b.id, :name => "benificiary_ids[]"%> </td>
</tr>
<% end %>
</table> <%= submit_tag "Approve", :class=>'form_buttons' %>
<% end %>
In controller,
#beneficiaries=Beneficiary.find(:all, :conditions => ["id IN (?)", params[:benificiary_ids]])
#beneficiaries.each do |b|
#beneficiaryloan = Beneficiaryloan.new(params[:beneficiaryloan])
#beneficiaryloan.beneficiary_id=b.id
#beneficiaryloan.hfi_id=session[:id].to_s
#beneficiaryloan.status_id=params[:status]
#beneficiaryloan.save
end
What I'm not getting is
params[:beneficiaryloan]
Values are coming as NULL
Am I missing something here in this form?
Check the following,
With the help of any browser tool(eg:firebug), make sure that the form has been rendered properly. Sometimes due to some misplaced tags(generally happens with table structure) the form does not renders properly.
Try to remove the table structure and see if the form works.
Make sure your association is fine, i guess it should be Beneficiary has many Beneficiaryloan
If none of the above helps, please post the request parameters over here.

Resources