Rails link_to if the association object is nil - ruby-on-rails

I'm continually getting errors where I can't link_to an object because it is not present. Usually the object, say a 'store' has a 'customer' so on the store show page I want to link to customers that have purchased there (through a 'sale' model).
For whatever reason the customer is no longer in the database so when I am doing a link_to warehouse.customer_id customer_path(warehouse) I am getting a no method error on nil or No route matches {:action=>"show", :controller=>"customers", :id=>nil} missing required keys: [:id]
Should I be doing link_to warehouse.customer_id customer_path(warehouse) if warehouse.customer.present? or putting an if statement around it so that I can show the customer_id instead of nothing so
<% if #contract.customer.present? %>
<p><%= link_to #contract.customer_id, customer_path(#contract.customer) %>
<% else %>
<p><%= #contract.customer_id %>
<% end %>
The second option looks messy and will clutter up my view but I don't want to not show the information if the object is not present :/
I also have a routing exception handler in place to redirect to root_url if the object does not exist in the database but that would mean making my link_to customer_path(warehouse.customer_id) instead of just customer_path(warehouse.customer).

link_to_if was created for cases similar to this.
link_to_if #contract.customer, #contract.customer_id, #contract.customer

Related

Ruby on Rails: Check_boxes for each item in a list

I'm trying to render simple check_boxes in a list of results so users can select on which of these results to get additional content for.
Example model setup (names changed):
UserRequest has_one :response
Response has_many :individual_results
IndividualResult has_one :contact_info
In the UserRequestsController I have a show action, which shows the user_request (duh), response, and its individual_results in a table.
The user should be able to select items (= contact_info) to request additional content for those. For some reason I don't manage to render the check_boxes after days of trying. Basically, I don't really understand where and how to store the array of selected contact_infos and how to pass it to the method that then gets the additional content.
My attempt was:
Create a ContactInfosController (didn't exist before, the user was only creating and showing her requests up to now, so contact_info was "model only" before)
Create a method request_content(contact_infos) (as post, to pass the user-selected contact_infos to. If I were to make it Restful, it would probably be "edit/update")
Add the form with check_boxes search_request#show
My search_request/show.html.erb:
<tbody>
<% if #response %>
<% form_for #contact_infos, url: contact_infos_request_content_path(#contact_infos) do |form| %>
<% #response.individual_results.each do |result| %>
# result.foo, ...
# result.contact_info.bar
<%= form.check_box "contact_info", "contact_info.request_content?", "true", "false %>
<% end %>
# form.submit
<% end %>
<% end %>
</tbody>
As it didn't work, I also had to declare the instance variable #contact_infos in RequestsController#show as #contact_infos = #response.individual_results.map { |r| r.contact_info }
Now, it fails at the check_box with "undefined method `merge'". Also, not sure how the params would be passed? I feel I went seriously "off the rails" and probably screwed up the design with this as it seems way too complicated...
Would anybody be so kind and help me get into the right direction, e.g., how would you pass the response to a method to request additional information? Read tons online but somehow couldn't apply it.
Thanks so much!

How to use link_to in Rails to fill out the id's

I have a problem. I am making a Rails app and it is a simple one. Customers and Invoices.
I am showing a Customer and their invoices. Iw ant to have a Details button to show the Details of an invoice.
But I dont know how to do it with link_to.
My route for the invoices is:
customer_invoice GET /customers/:customer_id/invoices/:id(.:format) invoices#show
And the code for the ink at the moment is:
<%= link_to 'Details', customer_invoice_path(#customer) %>
By doing this every detail button just tries to call
/customers/:customer_id/invoices/:customer_id
So the last :customer_id should be the id of the invoice but I dont know how to do it.
This didnt work:
<%= link_to 'Details', customer_invoice_path(#customer, #invoice) %>
and jsut gives me a "compile error" (is this the right term?) in the browser.
Any ideas?
Edit: Ok Ive got it by trial and error:
<%= link_to 'Details', customer_invoice_path(#customer, invoice.id) %>
I suppose your error is that you have invoice, but not #invoice (presumably, you're doing this in a #customer.invoices.each do |invoice| loop), in which case you should be able to do customer_invoice_path(#customer, invoice).

Get rails route to reflect database lisiting

I currently have a page that searched through a listings database. On clicking a selection, the view links to that listing's show page:
<div class="listings_wrapper">
<% #listings.each do |listing| %>
<%= link_to listing_url(listing), class: "listing_link" do %>
<div class="listing">
<div class="picture">
<% if listing.thumbnail != nil %>
<%= image_tag(listing.thumbnail, class: "list_image") %>
<% end %>
</div>
The show page that is currently routed as:
get 'listings/:listing_id', to: 'listings#show', as: 'listing'
which will get me the address
localhost3000/listing/612983618 (arbitrary id)
What I'm trying to do is get the route to display information from the database in the route instead, for SEO purposes:
localhost3000/listing/[address]/[booking_id]
When I try to adjust to
get 'listings/:listing_id', to: 'listings#show', as: 'listing/:address/:booking_id'
I get blocked on loading. I've been looking around stackoverflow at similar answers, but haven't got my head around this problem as of yet. Since the link is pulling the object itself, and the route is pulling the id from that, it would make sense to refer to the :address key instead, but something is clearly missing. Help?
In order to make the URI for listings#show to receive the address and booking_id of the object, then you could move the alias in your route definition to the uri argument, like:
get 'listing/:address/:booking_id', to: 'listings#show'
Now it'll be waiting both attributes. While in your controller if you want to find that specific object from both sent attributes, then you can use find_by:
#listing = Listing.find_by(adress: params[:address], booking_id: params[:booking_id])
#listings = Listing.last(3)
Note this will work, but in case you have more than one record with same address and booking_id, find_by will just return the first one.

how to pass a static string into a link_to as an argument in ruby on rails view

I have a modified string. Here is the code where I do the changes:
<% device=#devices.find(1) %>
<% #string ="" %>
<% device.attributes.keys.each do |attribute| %>
<% next if attribute == 'id' || attribute== 'token' || attribute =='carrier' || attribute =='segment' || attribute =='created_at' || attribute =='updated_at' %>
<% x=attribute.to_s %>
<%#string = #string + x +":device."+x +"," %>
<% end %>
<% #string %>
<% #arguments= #string.gsub(/\,$/, '') %>
<%= #arguments %>
It works and it is in the right format to put it in the link_to helper.
This is how I first wrote the link_to helper, and it worked.
<td><%= link_to 'Send notification', controller: "home", action: "send_notification", token: device.token, first_name: device.first_name, last_name: device.last_name %></td>
I tried to change it like this:
<td><%= link_to 'Send notification', controller: "home", action: "send_notification", token: device.token, #arguments %></td>
or #{arguments}
But it doesn't work. I even created another variable without # but it didn't work either.
How can I paste my arguments?
This is my arguments string btw:
"first_name:device.first_name,last_name:device.last_name,nickname:device.nickname"
What should I change?
Another simple newbie question; I feel like I am doing most of the coding in the wrong place. Is it right thatI write so many things in view?
What is the best approach in Ruby on Rails programming?
Thanks in advance
I'll answer your code question first and leave the string question for last.
First, some of your code is in the wrong places. Rails expects you to retrieve the database record in the controller and then pass it into the view. Something like:
devices_controller.rb
class DevicesController < InheritedResources::Base
def send_notification
#device = Device.find(id)
end
....
Then in your show view (app/views/devices/send_notification.html.erb) you can use the #device object and access its attributes like #device.first_name and #device.last_name and print them out or whatever.
Second, the link_to method needs a Hash of arguments, not a string. But either way, there is no use case in Rails that I can think of for passing the entire set of object attributes into the link_to method. It's just generating a link. You probably don't really want it to be littering your html elements with every one one of your record attributes.
All you need to do if you want access to that data when the user clicks the link is to pass the id in as a url element and then have the controller at the other end of the link (in your case Home?) catch the id and create an object out of it there.
I'd suggest taking a good look at: http://guides.rubyonrails.org/

Method Accesibility/Scope - NoMethodError

I'm working on my first rails project and I have a problem that I just cannot figure out.
I generated a Scaffold for an object named Archive
to this object I added the method processfile
when I try to link_to said method from Archives#Index I'm getting this:
undefined method `processfile' for #<Archive:0x702de78>
This is the model archive.rb
class Archive < ActiveRecord::Base
belongs_to :users
attr_accessible :file, :user_id
mount_uploader :file, FileUploader
end
This is the code on the index.html.erb (belonging to archives)
<% #archives.each do |archive| %>
<tr>
<td><%= archive.file%></td>
<td><%= User.find(archive.user_id).name %></td>
<td>
<%= link_to 'Download', archive.file_url %>
::
<%= link_to 'Show', archive %>
::
<%= link_to 'Edit', edit_archive_path(archive) %>
::
<%= link_to 'Delete', archive, confirm: 'Esta Seguro?', method: :delete %>
::
<%= link_to "Process", archive.processfile %>
</td>
</tr>
<% end %>
this is the routes.rb line:
match "archives/processfile/:id" => "archives#processfile", :as => :processfile
the processfile method defined whitin archives_controller.rb doesn't have anything on it, i just wanted to test the functionality since I'm having a hard time getting the grip of the "rails way"
archives_controler.rb
def processfile
# #archive = Archive.find(params[:id])
#do something with the archive
end
All in all, what I ultimately want to achieve is to call the processfile method on a given archive(taken from the index table) to do something with it. On the example, I watered down the method call (not passing an archive or archive.file to it) to make it run, to no avail.
I've searched a lot (on google and in here) and haven't found a clear guide that would address my problem, probably because i'm new and can't fully grasp the concepts behind rails MVC.
I've read something about methods only being accessed by same controlers but I've seen sample code when people call methods on controllers from index views without declaring them as helpers. o.0
I know it's probably a silly confusion, but I can't figure it out :(
The way you've structured your route (i.e., match "archives/processfile/:id" => "archives#processfile") means that it's expecting an archive id to be passed. You need to adjust your link_to to pass one:
# app/archives/index.html.erb
<%= link_to "Process", processfile_path(archive.id) %>
The error you're receiving is because you're trying to call an instance method called processfile on archive, but there's presumably no method by that name. The second parameter of the link_to helper is a path, not an instance method.
EDIT:
If you're looking to make your routes more RESTful (which you should do if you've created an Archive resource), you can generate all your CRUD routes by declaring resource :archives in your routes. Then, within a block, you can declare a block of member routes, all of which will route to the specified action in your archive_controller.rb and enable you to pass an archive id to the action.
# config/routes.rb
resources :archives do
member do
get 'processfile'
end
end
You added the processfile method to your ArchiveController. That does not make the method available to the Archive model. If you want the method to be available to instances of Archive models then you need to put it inside the model as an instance method.
If you what you want to do is place a route to the action processfile in your ArchiveController then you can do so by adding link_to "Process", processfile_path(id: archive.id)

Resources