Ruby on Rails Access column from belongs_to table - ruby-on-rails-4

I'm developing a CRUD and I have three tables clients, audit_cases and ra_cases.
The followings are the relationship of my models
class Client < ActiveRecord::Base
has_many :audit_cases
end
class AuditCase < ActiveRecord::Base
belongs_to :client
has_many :ra_cases
end
class RaCase < ActiveRecord::Base
belongs_to :audit_case
end
Model
def index
#a_cases = AuditCase.all
#b_cases = RaCase.all
end
I'm trying to join these three tables and show in a view
The following script works successfully
<tbody>
<% #b_cases.each do |b_case| %>
<tr>
<td><%= b_case.audit_case.client.Client_name %></td>
</tr>
<% end %>
</tbody>
But the following script have an error of undefined method `Client_name' for nil:NilClass
<tbody>
<% #a_cases.each do |a_case| %>
<tr>
<td><%= a_case.client.Client_name %></td>
</tr>
<% end %>
</tbody>
I can get the client array 'Client:0x007ff7d662adb0' if I use
<%= a_case.client %>
I'd like to know how could I modify my script if I want to extract parent's data from child(audit_cases) instead of from grandchild(ra_cases).
Thank you very much!

Due to some of the column "client.Client_name" are nil,
It works after I add this code "unless a_case.client.nil?"
<%= a_case.client.Client_name unless a_case.client.nil? %>

It doesn't look like each relation is required, so there may be some AuditCase records in your database that don't have Client records associated with them (or the Client record was destroyed). The consequence of that is that your view will raise an error because it tries to call a method on nil.
To get the view working, I would nil-guard it in some way. If you want to enforce a requirement around the client-case relationship, that's a different issue.
Here are some possible nil guard ideas:
# If you're using Ruby 2.3+, you can use the Safe Navigation Operator
<tbody>
<% #a_cases.each do |a_case| %>
<tr>
<td><%= a_case.client&.Client_name %></td>
</tr>
<% end %>
</tbody>
# Rails also provides a #try method
<tbody>
<% #a_cases.each do |a_case| %>
<tr>
<td><%= a_case.client.try(:Client_name) %></td>
</tr>
<% end %>
</tbody>
# or just a rough nil check
<tbody>
<% #a_cases.each do |a_case| %>
<tr>
<td><%= a_case.client.Client_name if a_case.client %></td>
</tr>
<% end %>
</tbody>
Let me know if that works.
From a ruby style perspective, I would avoid capitalizing methods like Client_name. Capitalization defines a constant/class in ruby.

Related

Rails not passing id

im new with rails. currently im facing problem with it. i have 3 model which is
order, task, and order task.
in the ordertask, i try to pass id from show.html to edit.html, but the rails only pass
http://localhost:3000/orders_tasks/%23%3COrderTask::ActiveRecord_Relation:0x00000009c9a078%3E/edit
instead of id number.
here is my show.html.erb
<p id="notice"><%= notice %></p>
<table class="table table-hover">
<tr>
<td>Task
</td>
<td>Status:
</td>
</tr>
<tr>
<% #status.each do |i| %>
<td><%= i.task_id %>
</td>
<td><%= i.status %>
</td>
</tr>
<% end %>
</table>
<%= link_to 'Edit', edit_orders_task_path(#status) %> |
<%= link_to 'Back', orders_tasks_path %>
here is my ordertask controller
class OrdersTasksController < ApplicationController
before_action :set_status, only: [:show, :edit, :update]
def index
#orders = Order.all
#status = OrderTask.includes(:task,:order).where(order_id: params[:id])
end
def edit
end
def show
end
def update
respond_to do |format|
if #status.update(order_params)
format.html { redirect_to #status, notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_status
#status = OrderTask.includes(:task,:order).where(order_id: params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order_task,:order).permit(:order_id,:status)
end
end
and here is my edit.html
<%= form_for(#status, html: {class: 'form form-horizontal'}).first.id do |f| %>
<% if #status.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#status.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% #status.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<table class="table table-hover">
<tr>
<td><%= f.label "List of task" %>
</td>
<td><%= f.label "Status" %>
</td>
</tr>
<tr>
<td><%= f.task_id %>
</td>
<td><div class="dropdown">
<%= f.select(:status,['In progress', 'Completed'], {}, {class: "control"})%> </div>
</td>
</tr>
<tr>
<td>
</td>
<td><%= f.submit %>
</td>
</tr>
</table>
<% end %>
my order model
class Order < ActiveRecord::Base
belongs_to :staff
belongs_to :customer
belongs_to :service
has_many :order_task
has_many :tasks , through: :order_task
validates :staff_id , presence: true
end
my task model
class Task < ActiveRecord::Base
has_many :order_task
has_many :orders , through: :order_task
attr_accessor :status, :task_type
validates :task_name, presence: true, uniqueness: true
end
and lastly my order task model
class OrderTask < ActiveRecord::Base
self.primary_key = [:order_id]
self.table_name = "Orders_tasks"
belongs_to :order
belongs_to :task
end
i hope you guys can help me out cause i have stuck with this problem for a week now. :D
You should place the edit links in the loop... since #status contains multiple ordertaks, and each ordertask should have his own edit page:
<p id="notice"><%= notice %></p>
<table class="table table-hover">
<tr>
<td>Task
</td>
<td>Status:
</td>
<td>Action:</td>
</tr>
<tr>
<% #status.each do |i| %>
<td><%= i.task_id %>
</td>
<td><%= i.status %>
</td>
<td><%= link_to 'Edit', edit_orders_task_path(i) %></td>
</tr>
<% end %>
</table>
<%= link_to 'Back', orders_tasks_path %>
Edit: But I do like to point out that most of the time you're not in need of Controllers for your join models. So I do not know why you think you need it, most of the logic can be build from either the OrdersController or the TasksController.

Ransack Undefined Method _path Rails 4.2.1

I'm working on a very simple CRUD Asset Management app and I want to use Ransack. I think I have this setup properly in my view and controller but each time the index view is hit I get the exception:
undefined methodassets_path' for #<#:0x007fa5f353e9e0>`
Here is my view:
index.html.erb
<div class="pull-right">
<%= search_form_for #q do |f| %>
<%= f.search_field :asset_name_cont, placeholder: 'Search...' %>
<% end %>
<table class="table table-striped">
<thead>
<tr>
<th>Asset Number</th>
<th>Asset Name</th>
<th>Serial Number</th>
<th>Model</th>
<th>Manufacturer</th>
<th>Asset Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #assets.each do |a| %>
<tr>
<td><%= a.asset_number %></td>
<td><%= a.asset_name %></td>
<td><%= a.asset_serial %></td>
<td><%= a.asset_model %></td>
<td><%= a.asset_manuf %></td>
<td><%= a.asset_type.try(:name) %></td>
<td><%= link_to 'View', inventory_path(a), :class => 'btn btn-mini btn-info' %> <%= link_to 'Edit', edit_inventory_path(a), :class => 'btn btn-mini btn-warning' %></td>
</tr>
</tbody>
<% end %>
<%= will_paginate #assets %>
Here is my controller excerpt:
inventory_controller.rb
def index
#q = Asset.ransack(params[:q])
#assets = #q.result.order("asset_number ASC").paginate(:page => params[:page], :per_page => 10)
end
And here is my model (with annotation of the fields)
asset.rb
id :integer not null, primary key
asset_number :string
asset_shortname :string
asset_name :string
asset_desc :text
asset_serial :string
asset_model :string
asset_manuf :string
asset_type_id :integer
created_at :datetime not null
updated_at :datetime not null
asset_location :string
class Asset < ActiveRecord::Base
extend FriendlyId
friendly_id :asset_name, use: :slugged
validates :asset_name, :asset_serial, :asset_type_id, :asset_model, :asset_manuf, :presence => true
belongs_to :asset_type
end
I think I have the controller wired up fine, I was having issues before with forms and routes by having a controller called assets which is an issue as a reserved name in Rails 4.x.x so I rebuilt the controller as inventory and call the Asset class from within.
My question is, I the search_form_for field to look at the Asset model's field for asset_name but when I write the view as I've laid out I constantly get that path error.
Is there a way to pass a different path into the Ransack search_field method so that I can get past what seems to be an issue with conventions?
If you need more information or if my question is not clear enough, please do not hesitate to edit or ask for more information. Thanks all!
Ok, I figured this out. Similar to issues I was seeing with breaking Rails naming conventions in my other forms, I had to pass the url and method in the search_form_for helper method. It's working!
Here's my view for the search now:
<%= search_form_for(#q, url: "/inventory", method: :get) do |f| %>
<%= f.search_field :asset_name_cont, placeholder: 'Search...' %>
<% end %>

WKHTMLTOPDF with pdfkit on Rails ignoring table page breaks

I know there are a lot of issues with wkhtmltopdf and page breaks that date back years, but I haven't worked out a solution yet. I'm using the PDFKit gem to generate my html pages into pdfs, but I don't want the pages to break in the middle of a table row.
I'm using wkhtmltopdf-binary (0.9.9.3), which looks to be the most updated version
My CSS:
#media print {
#scores table tr td, #scores table tr th {
page-break-inside: avoid !important;
}
table, tr, td, th, tbody, thead, tfoot {
page-break-inside: avoid !important;
}
}
My table:
<div class="score_table">
<table id="scores" class="print-friendly">
<tbody>
<% #chapters.each do |chapter| %>
<tr>
<th colspan="3" ><%= chapter.name %></th>
</tr>
<% chapter.rules.each do |rule| %>
<tr>
<th colspan="2" >Rule: <%= rule.name %></th>
<th></th>
</tr>
<!-- Triggers -->
<% rule.triggers.each do |trigger| %>
<tr>
<td>T</td>
<td><%= markdown(trigger.body) %></td>
<td><%= markdown(trigger.explanation) %></td>
</tr>
<% if trigger.image? || trigger.image2? %>
<tr>
<td></td>
<% if trigger.image? %>
<td><%= image_tag trigger.image.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
<% if trigger.image2? %>
<td><%= image_tag trigger.image2.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
</tr>
<% end %>
<% end %>
<!-- Questions -->
<% rule.questions.each do |question| %>
<tr>
<td>Q</td>
<td><%= markdown(question.body) %></td>
<td><%= markdown(question.answer) %></td>
</tr>
<% if question.image? || question.image2? %>
<tr>
<td></td>
<% if question.image? %>
<td><%= image_tag question.image.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
<% if question.image2? %>
<td><%= image_tag question.image2.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
</tr>
<% end %>
<% end %>
<!-- Hints -->
<% rule.hints.each do |hint| %>
<tr>
<td>H</td>
<td><%= markdown(hint.body) %></td>
<td><%= markdown(hint.explanation) %></td>
</tr>
<% if hint.image? || hint.image2? %>
<tr>
<td></td>
<% if hint.image? %>
<td><%= image_tag hint.image.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
<% if hint.image2? %>
<td><%= image_tag hint.image2.url(:thumb) %></td>
<% else %>
<td></td>
<% end %>
</tr>
<% end %>
<% end %>
<% end %>
<% end %>
</tbody>
</table>
</div>
Is there a work around, or is there something that I'm doing wrong? This is the result:
I could post the PDFKit code as well, but it sounds like a wkhtmltopdf issue
***Update - My CSS #print isn't affecting the page when .pdf is added to the url. I have my stylesheet link with media: "all"
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
Here's my initializer pdfkit.rb:
ActionController::Base.asset_host = Proc.new { |source, request|
if request.env["REQUEST_PATH"].include? ".pdf"
"file://#{Rails.root.join('public')}"
else
"#{request.protocol}#{request.host_with_port}"
end
}
If I can fix the CSS, then I probably will solve the page break issue!
i added this in css it worked for me
#media print {
#scores {
page-break-before: always;
}
}
I am using version wkhtmltopdf 0.12.0
For me, page breaks ONLY work with --print-media-type.
Without it, page break protection for images works, but not page-break-after or before.
I had to make a special css file for print media to get it work.
Setting the paper size to 'A3' or using the 'overflow: visible' didn't make any difference.
I ended up with the following:
in config/initializers:
PDFKit.configure do |config|
config.wkhtmltopdf = '/usr/bin/wkhtmltopdf'
config.default_options = {
:encoding=>"UTF-8",
:page_size => 'A3',
:zoom => 0.9,
:javascript_delay => 2000,
:print_media_type => true,
:footer_right => 'report, page [page] of [toPage]',
:no_background => true,
}
end
I am not 100% sure if the no_background is needed.
Then, in the controller:
def report_as_pdf
require 'nokogiri'
root_url = Rails.env.development? ? 'http://localhost:3000' : 'https://my.example.com'
html = render_to_string(layout: true, template: "reports/report_as_pdf").gsub('/assets', root_url + '/assets') # since wkhtmltopdf can not find the css files, we add the root_url to all assets
html_doc = Nokogiri::HTML(html)
html_doc.css('div.contain-to-grid').remove
html_doc.css('nav#rapportage_bar').remove
# Had to remove certain elements on the page. Not relevant for this particular problem, but it may help.
html = html_doc.to_html
filename = 'report_' + Time.now.to_s(:db)[0..9]
if Rails.env.development?
File.write("/tmp/#{filename}.html", html)
render :text => "wrote /tmp/#{filename}.html"
fork do
system("wkhtmltopdf --footer-right 'report, page [page] of [toPage]' --page-size 'A3' --zoom 0.9 --javascript-delay 2000 --no-background --print-media-type file:////tmp/#{filename}.html /tmp/#{filename}.pdf")
end
# forking was the only way I could get it to work in development mode, using thin as webserver instead of webrick (but it might work with webrick, I didn't try).
else
kit = PDFKit.new(html)
send_data(kit.to_pdf, :filename => filename + '.pdf', :type => 'application/pdf')
# all is simpeler in production mode.
end
end
Note, that in the default layout (normally app/views/layouts/application.html.erb) I added one line to introduce a special css file for print:
stylesheet_link_tag "application_print", media: "print"
This file actually imports some tables from ZURB Foundation, which is cool.
#import "foundation/components/tables";
h1 {
font-variant: small-caps;
font-weight: bolder;
font-size: 320%;
border-bottom: 12px solid black;
margin-bottom: 20px;
margin-top: 80px;
}
h2 { (etc etc etc)
To make page breaks in a view, I just insert this in the right places:
I hope this will be useful to someone someday.
Can you upload the controller code where you've called PDFkit.new ?
Your stylesheet might not be included.
Try adding the stylesheet in your controller code like this:
def export
kit = PDFKit.new(render_to_string(layout: false, handlers: [:haml], formats: :html, template: 'score_tables/export'))
kit.stylesheets << "#{Rails.root}/vendor/assets/stylesheets/bootstrap.css"
kit.stylesheets << "#{Rails.root}/app/assets/stylesheets/score_tables.css"
kit
end
Here is how I fixed my issue.
- Updated PDFKIT to as of ( 01/22/2014 )
- I had to move my table out of the <div> as the nested table messes everything up.
Example:
No div tag wrapping the table.
From
<div class="score_table">
<table id="scores" class="print-friendly">
...rest of the HTML
To
<table id="scores" class="print-friendly">
...rest of the HTML
Hope this helps.

View loop with nested params

Working on the Domain view. I would like to loop through and list all Domains, all controls and any goals that are under those controls. I cannot figure out how to loop through the controls goals. Current solution just loops through all the goals, not just the goals that we connected to the Control
class Domain < ActiveRecord::Base
has_and_belongs_to_many :controls
class Control < ActiveRecord::Base
has_and_belongs_to_many :domains
has_many :goals
class Goal < ActiveRecord::Base
belongs_to :control
def index #domain controller
#domains = Domain.all
#controls = Control.all
#goals = Goal.all
end
domain index view
<% #domains.each do |domain| %>
<tr>
<td><%= domain.domainName %></td>
<% domain.controls.each do |control| %>
<td><%= control.controlName %></td>
<% #goals.each do |t| %>
<td>SG<%= t.goalsNumber %>, </td>
<% end %>
<% end %>
This is what I came up with. Probably not the most efficient way to do this but it works for now
<% domain.controls.each do |control| %>
<td>
<h3><%= control.controlName %></h3>
</td>
</tr>
<% #goals.each do |goals| %>
<% if goals.control.controlName==c ontrol.controlName %>
<tr>
<td>SG
<%=g oals.goalsNumber %>
<%=g oals.goalsName %>
</td>
</tr>
<% else %>
<% end %>
<% end %>
<% end %>

RUBY-RAILS 4 UPDATE MODEL

I want to update a model on my db. if an user checked the checkbox, it must not be appear again on the view.
I have some view like this:
<%= form_tag( riepilogo_path, method: "post", id: "sel") do %>
<%= hidden_field_tag "sala", params[:sala] %>
<%= hidden_field_tag "spectacle_id", params[:spectacle_id] %>
<%= hidden_field_tag "num", params[:num] %>
<table>
<tr>
<th></th>
<th>Numero</th>
</tr>
<% for posti in #postis %>
<tr>
<td><%= check_box_tag "posti_ids[]", posti.id %></td>
<td><%=h posti.numero %></td>
</tr>
<% end %>
</table>
<%= submit_tag "OK", id: "sub"%>
<% end %>
controller of Postis is something like so:
class PostisController < ApplicationController
def index
#postis = Posti.where(:stato => "unchecked" , :spectacle_id => params[:spectacle_id] , :hall_num => params[:sala])
end
def posti_multiple
#postis = Posti.find(params[:posti_ids])
end
end
In the Posti's model i have attributes: spectacle_id, hall_num, seat(integer) and stato (:default => "unchecked").
When he submit, seats be load in posti_ids[]. I want to update stato of seats which are present in posti_ids from "unchecked" to "checked".
As per your comment,you have tried to perform update_column on an Array.So is the error
undefined method `update_column' for # Array:0xb881584
Here #postis returns.You should be giving it like this
Posti.update_column(stato: "checked")