How to result and validate associated data from multiple Table cells - ruby-on-rails

Example: 2 tables
Table 1:
"Orders"
cells:
-id
-etc
-etc
Table 2:
"Sales_uploads"
cells:
-id
-order_id (same data as "id" in Orders table)
-etc
-etc
I have created =
Order.where(id: Sales_upload.pluck(:order_id))
from Googling, but haven't figured out where to go from here.
I have this def in my sales_upload model:
def order_sales_relationship
Order.where(id: Sales_upload.pluck(:order_id))
end
Then in the views I have: (a portion of views)
<% #orders.each do |order| %>
<tbody>
<tr>
<td class="center"><%= order.buyer.name %></td>
<td class="center"><%= number_to_currency(order.listing.price) %></td>
<td class="center"><%= order.created_at.strftime("%B %-d, %Y") %></td>
<td class="center">
<div class="field">
<% if #order_sales_relationship = true %>
<%= link_to '/sales' %>
<% else %>
<%= link_to "Upload", new_order_sales_upload_path( order, #order ), class: "btn btn-primary" %>
<% end %>
When i use this, '/sales' appears in the upload section of the table even if nothing has been uploaded. I believe the model is incorrect and may jst be validating if the cells exist, but not validating if they also match. How would i validate the matching as wlel (if this is even true)
The goal is to display an upload link ONLY if the upload hasn't happened yet. If it has, I want only an update/edit link (which is '/sales' atm as a placer, that's a whole other issue).

ok from what I'm understanding, please correct me
change
def order_sales_relationship
Order.where(id: Sales_upload.pluck(:order_id))
end
to
def order_sales_relationship
#order_sales = Order.where(id: Sales_upload.pluck(:order_id))
end
in view make this changes
<% if #order_sales.present? %>
and
<%= link_to "Upload", new_order_sales_upload_path(order, #order), class: "btn btn-primary" %>
??? where is #order

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

Conditional hidden tag based on checkbox condition in Rails

How can I send a hidden tag based on whether or not a checkbox is checked?
I have a table with a product title and product price and check box selection on each row and on the form submit I'd like to send both of these values to a controller. I was only able to get one value to submit with a single checkbox, so I added a hidden tag field, however, this hidden tag will submit every row, which is not what I want. In the params sent example below it should have two items and two prices sent, but it sends all the prices for each row. (As an aside, if there is a better way to send both params without using a hidden tag please let me know!)
This is data from a google analytics API report request FYI =>
#product_revenue.reports[0].data.rows
p.dimensions[0] = "Product Title"
p.metrics[0].values[0] = "Product Price"
The structure of this comes from here.
View Code:
<div class="col-md-6">
<%= form_tag add_multiple_path, method: :post do %>
<table>
<thead>
<th><strong>Product Title</strong></th>
<th><strong>Product Price</strong></th>
<th><strong>Add?</strong></th>
</thead>
<% #product_revenue.reports[0].data.rows.each do |p| %>
<tr>
<td><%= p.dimensions[0] %></td>
<td><%= p.metrics[0].values[0] %></td>
<td>
<%= check_box_tag 'price_test_datum[product_title][]', p.dimensions[0] %>
<%= hidden_field_tag('price_test_datum[product_price][]', p.metrics[0].values[0]) %>
</td>
</tr>
<% end %>
</table>
<%= submit_tag "Add selected" %>
<% end %>
</div>
The hidden field is dumping all of the column values instead of the one associated with that row?
Parameters sent:
{
"utf8"=>"✓",
"authenticity_token"=>"token here",
"price_test_datum"=>{
"product_price"=>["29.98", "14.99", "14.99", "14.99", "14.99", "14.99", "299.95", "35.97", "21.98", "10.99", "33.98", "27.98", "13.99", "59.99", "29.98", "59.98", "29.99", "110.93", "4088.79"],
"product_title"=>["Turquoise Bracelets", "Red Bracelets"]
},
"commit"=>"Add selected"
}
So I added an index to the table loop and used the checkbox value to submit the relevant row value (index) to the controller. I then used hidden tag fields to send all the product title and price values in as arrays to the controller and used the row key to find the relevant value. This seems like an inelegant solution, but it worked.
<%= form_tag add_multiple_path, method: :post do %>
<table>
<thead>
<th><strong>Product Title</strong></th>
<th><strong>Product Price</strong></th>
<th><strong>Add?</strong></th>
</thead>
<% #product_revenue.reports[0].data.rows.each_with_index do |p, index| %>
<tr>
<td><%= p.dimensions[0] %></td>
<td><%= p.metrics[0].values[0] %></td>
<td>
<%= check_box_tag 'row[]', index %>
<%= hidden_field_tag 'price_test_datum[product_title][]', p.dimensions[0] %>
<%= hidden_field_tag 'price_test_datum[product_price][]', p.metrics[0].values[0] %>
</td>
</tr>
<% end %>
</table>
Controller Code
def add_multiple
params[:row].each do |r|
PriceTestDatum.create(product_title: params[:price_test_datum][:product_title][r.to_i],
product_price: params[:price_test_datum][:product_price][r.to_i])
end
respond_to do |format|
format.html { redirect_to price_test_data_path }
format.json { head :no_content }
end
end

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

Create/New DB record for each generated set of fields

I have got a problem with saving multiple record.
This script wil load a list of instruments that belong to a department through a join table.
This form will make a new record for another join table, the problem is when I'f got 4 instruments it only will save the last instrument.
Image generated list
Can anybody help me out to solve this problem or point me into the right direction ??
<%= form_for(:joindaylisting) do |j| %>
<% #instrumentslist.each do |instrument| %>
<tr class="<%= cycle('odd', 'even') %>">
<td>
<% j.label(:instrument_id, "#{instrument.name}") %>
<%= link_to("#{instrument.name}", {:controller => 'instruments', :action => 'show_instruction', :instrument_id => instrument.id}, :onclick=>"window.open('height=670, width=675');return false;") %>
</td>
<%= j.hidden_field(:instrument_id, :value => instrument.id) %>
<td></td>
<% j.label(:ammountdesinfection, "") %>
<td><%= j.text_field(:ammountdesinfection) %></td>
<% j.label(:ammountinstruments, "") %>
<td><%= j.text_field(:ammountinstruments) %></td>
<% j.label(:ammountrelease, "") %>
<td><%= j.text_field(:ammountrelease) %></td>
<% j.label(:notes, "") %>
<td><%= j.text_area(:notes) %></td>
</tr>
<% j.label(:department_id) %>
<%= j.hidden_field(:department_id, :value => #department.id) %>
<% end %>
<% end %>
Only the last one is saved because the fields have the same name and the last one overrides all other values. See the params you are getting on the receiving controller.
You probably want/need to configure departments to accepts_nested_attributes_for :instruments and a form for the department object with fields_for: instruments. I've highlighted keywords that my help you get the information you want, the Rails Guides is a good place to start.

Removing conditional logic from a shared partial view or alternative solution

For a current project, I have duplicate code between views, and I'm not sure of the best route to refactor it.
I appear to be in a position where I can have duplicate code across various .html.erb files, or I could put identical code into a partial and use conditionals. I've always heard logic should stay out of views. Neither option seems ideal, and I don't currently know of alternatives.
To illustrate my question, I created a simple rails app called animals. I scaffolded for two models: one for cat and one for dog. Images display their corresponding attributes:
Displaying #cats and #dogs is pretty much the same. Cats just have a column for meows while Dogs have a column for barks, and a dog has the additional attribute column of plays_catch.
Lets say we choose to reduce the duplicate code for displaying cats and dogs by making a shared view partial:
#views/shared/_animal.html.erb
<tr>
<td><%= animal.name %></td>
<td><%= animal.age %> </td>
<% if animal.class == Cat %>
<td><%= animal.meows %> </td>
<% end %>
<% if animal.class == Dog %>
<td><%= animal.barks %> </td>
<td><%= animal.plays_catch %> </td>
<% end %>
</tr>
Then to render #cats = Cat.all:
<%= render partial: "shared/animal", collection: #cats %>
Then to render #dogs = Dog.all:
<%= render partial: "shared/animal", collection: #dogs %>
Obviously it would be overkill to do something like this for this specific example, but the real world project I'm applying it to would not be overkill.
The overall question is: how do you remove nearly identical code that iterates over collections, where the only difference is adding/removing a column of information? It just doesn't feel right to put that logic in the view itself, and leaving the duplication feels wrong.
You could use decorators and add methods that return the extra column(s):
class DogDecorator < Draper::Decorator
def extra_columns
[:barks, plays_catch]
end
end
class CatDecorator < Draper::Decorator
def extra_columns
[:meows]
end
end
...
<% animal.extra_columns.each do |column| %>
<td><%= animal.attributes[column.to_s] %>
<% end %>
...
<% #cats = CatDecorator.decorate_collection(Cat.all)
<%= render partial: "shared/animal", collection: #cats %>
You can use respond_to? to solve the problem more generically. The view logic doesn't feel so wrong when it's more generic.
<% [:meows, :barks, :plays_catch].each do |method| %>
<% if animal.respond_to?(method) %>
<td><%= animal.send(method) %> </td>
<% end %>
<% end %>
You can add a method of the same name to both Cat and Dog classes which would return the specific instance attributes names and values. I'd recommend returning two arrays (one with the names of the fields, other with the fields' values, or vice-versa) since hashes are not exactly ordered. This way you can control the order in which they'll appear in the view.
For example:
#models/cat.rb
def fields_and_attributes
fields = ["Name","Age","Meows"]
attributes = [self.name, self.age]
if self.meows
attributes.push("Yes")
else
attributes.push("No")
end
[fields,attributes] # make sure each attribute is positioned in the same index of its corresponding field
end
#models/dog.rb
def fields_and_attributes
fields = ["Name","Age","Plays catch"]
attributes = [self.name, self.age]
if self.plays_catch
attributes.push("Yes")
else
attributes.push("No")
end
[fields,attributes] # make sure each attribute is positioned in the same index of its corresponding field
end
#controllers/animals_controller.rb
def display_animals
#animals = Cat.all + Dog.all # an array containing the different animals
end
#views/display_animals.html.erb
for i in (0...#animals.size)
fields_and_attributes = #animals[i].fields_and_attributes
for f in (0...fields_and_attributes[0].size)
<p><%= fields_and_attributes[0][f] %> : <%= fields_and_attributes[1][f] %></p>
end
end
Here, we first iterate over all of the animals and call the .fields_and_attributes method of that specific record; we then iterate over the results of calling that method, displaying fields and attributes in the same order as the one defined within the method and also guaranteeing that the code will display every field and every attribute regardless of the difference in the total number of fields for each different animal.
I don't know of any canonical way to accomplish this, but I would use one partial for this in the following way:
<tr>
<% animal.attributes.each do |_, value| %>
<td><%= value %></td>
<% end %>
</tr>
You can get rid of repeated attributes calls by providing in the partial a local variable with pre-obtained model attributes.
EDIT: if you only want to display some attributes.
# Declare whitelist of attributes
# (you can also declare a blacklist and just calculate the difference between two array: all_attributes - blacklist_attributes):
<% whitelist = [:name, :age, :barks] %>
<%= render partial: 'shared/animal',
collection: #dogs,
locals: {attrs: (#dogs.first.attributes.keys.map(&:to_sym) & whitelist)} %>
views/shared/_animal.html.erb:
<tr>
<% attrs.each do |attr| %>
<td><%= animal[attr] %></td>
<% end %>
</tr>
Below is my answer after reviewing posted answers. Basically:
I left the differences within each scaffold model's index page
I made shared partials for common table headers and table data
code below:
#app/views/cats/index.html.erb
<h1>Listing Cats</h1>
<table>
<thead>
<tr>
<%= render partial: "shared/cat_dog_table_headers" %>
<th>Meows</th>
</tr>
</thead>
<tbody>
<% #cats.each do |cat| %>
<tr>
<%= render partial: "shared/cat_dog_table_data", locals: {animal: cat} %>
<td><%= cat.meows %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Cat', new_cat_path %>
And for the dogs:
#app/views/dogs/index.html.erb
<h1>Listing Dogs</h1>
<table>
<thead>
<tr>
<%= render partial: "shared/cat_dog_table_headers" %>
<th>Barks</th>
<th>Plays catch</th>
</tr>
</thead>
<tbody>
<% #dogs.each do |dog| %>
<tr>
<%= render partial: "shared/cat_dog_table_data", locals: {animal: dog} %>
<td><%= dog.barks %></td>
<td><%= dog.plays_catch %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Dog', new_dog_path %>
The shared table headers for cats and dogs:
#app/views/shared/_cat_dog_table_headers
<td><%= Name %></td>
<td><%= Age %></td>
The shared table data for cats and dogs:
#app/views/shared/_cat_dog_table_data_headers
<td><%= animal.name %></td>
<td><%= animal.age %></td>

Resources