Capturing a nil object and rendering a view - ruby-on-rails

I seem to be unable to capture a nil response from my api call, when there are no results I get this error
undefined method `[]' for nil:NilClass
So if this happens I would like to show a message like 'No book found', so i have tried these
<% if #results.empty? %>
<% if #results.nil? %>
<% if #results.nil %>
but none of them capture the error
Controller
def results
results = book_search(params[:search])
#results = results
#book = Book.new
#book.author = results.first["artistName"]
#book.bookname = results.first["trackName"]
#book.image = results.first["artworkUrl100"].gsub("100x100-75.jpg", "200x200-75.jpg")
#book.description = results.first["description"]
end
View
<div class="container">
<div class="row">
<div class="span8 offset2">
<% if #results.nil? %>
<h1 class="resultTitle">sorry we can't find anything for that book.</h1>
<%= link_to "Back To Search", root_path, :class => 'backButton' %>
<% end %>
<%= #results.first["trackName"] %> <br>
<img src =<%= #results.first["artworkUrl100"] %>> <br>
<%= #results.first["artistName"] %> <br>
<%= truncate(remove_tags(#results.first["description"]), :length => 250) %> <br>
<%= form_for #book do |f| %>
<%= f.label :category_id, "Category" %>
<%= f.collection_select(:category_id, Category.all, :id, :name, :prompt => 'Please select a Category') %>
<%= f.hidden_field :author %>
<%= f.hidden_field :bookname %>
<%= f.hidden_field :image %>
<%= f.hidden_field :description %>
<%= f.submit 'Save book' %>
<% end %>
</div>
</div>
</div>
Any ideas on what it could be
Thanks

The latter version will return true if #results is nil. You have some other error elsewhere.
If the error still shows up, then you access results even when #results.nil? returns true. More specifically take a look at the places where you call the square bracket operator [] as the error is caused by one of them.
EDIT: after discussion in chat we have discovered the problem. First in the conroller book_search returns an empty array and then, when invoking results.first["artistName"] this causes the error, because results.first is nil. So to fix that we added the following to the controller:
def results
results = book_search(params[:search])
#results = results
unless #results.empty?
#book = Book.new
#book.author = results.first["artistName"]
#book.bookname = results.first["trackName"]
#book.image = results.first["artworkUrl100"].gsub("100x100-75.jpg", "200x200-75.jpg")
#book.description = results.first["description"]
end
end
I.e. a check to only create a new book and set its properties if a book was found. Now in the view, a check should be added to only render the rest of the view(the part that invokes [] operator on #results if results is not empty. This is achieved using an else statement:
<div class="container">
<div class="row">
<div class="span8 offset2">
<% if #results.empty? %>
<h1 class="resultTitle">sorry we can't find anything for that book.</h1>
<%= link_to "Back To Search", root_path, :class => 'backButton' %>
<% else %> <--- I've putted an else instead of end here!!!
<%= #results.first["trackName"] %> <br>
<img src =<%= #results.first["artworkUrl100"] %>> <br>
<%= #results.first["artistName"] %> <br>
<%= truncate(remove_tags(#results.first["description"]), :length => 250) %> <br>
<%= form_for #book do |f| %>
<%= f.label :category_id, "Category" %>
<%= f.collection_select(:category_id, Category.all, :id, :name, :prompt => 'Please select a Category') %>
<%= f.hidden_field :author %>
<%= f.hidden_field :bookname %>
<%= f.hidden_field :image %>
<%= f.hidden_field :description %>
<%= f.submit 'Save book' %>
<% end %>
<%end %> <--- Added an end for the if-else here.
</div>
</div>
</div>
So I have added an else and an end that I have indicated in the code. Why do you need to do that? Well because even after performing the check and displaying the message, the rest of the page was still evaluated and this bit: %= #results.first["trackName"] %> <br> was causing the error. You should not try to call the [] operator if you know #results is empty. The new version only displays the remaining part of the page in the else case i.e. if #results is not empty.
Hope this makes it clear.

Related

How to insert new line breaks using form_for with collection_check_boxes

I use the following form_for at one point in my code to display a series of topics for users to select from.
<%= form_for #user do |f| %>
<%= f.collection_check_boxes(:topic_ids, Topic.all.sample(50).each, :id, :topic_name) %>
<%= f.submit %>
<% end %>
When it renders on the page, the boxes are all one-after-the-other. How can I separate them so that there is one check box per line?
from reference here
It is possibly to customize the way the elements will be shown by giving a block to the method as sample below from your code above
<%= form_for #user do |f| %>
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, :topic_name do |b| %>
<%= b.label(class: "check_box") do %>
<%= b.check_box(class: "check_box") %>
<%= b.object.topic_name %></br>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You may of course render HTML inside the block:
<%= form_for #user do |f| %>
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, : topic_name do |b| %>
<div class="my-checkbox-wrapper">
<%= b.label(class: "foo") do %>
<%= b.object.topic_name %>
<%= b.check_box(class: "bar") ></br>
<%end%>
<%= f.submit %>
<%end%>
You can have a look at this example
It is very broad question. In short, using CSS.
For example using Bootstrap 4:
<%= form_for #user do |f| %>
<div class="form-check">
<%= f.collection_check_boxes :topic_ids, Topic.all.sample(50).each, :id, :topic_name, class: 'form-check-input' %>
</div>
<%= f.submit %>
<% end %>

Rails 4 not rendering code

I am trying to render a partial on a page in rails. For some reason the code is not being rendered into html. I have tried taking it out of the partial and just placing it in the profile page but still nothing. I am getting no errors and have restarted the server but still nothing. This is in development mode. Also all code except the message code works fine. Any help would be appreciated. Here is the code.
profile.html.erb
<% unless #pictures.nil? %>
<div id="container" style="width: 500px; height: 450px;">
<div id="slides">
<% #pictures.each do |picture| %>
<%= image_tag(picture.image.url(:thumbnail)) %>
<% end %>
<%= image_tag("left.png") %>
<%= image_tag("right.jpeg") %>
</div>
</div>
<% end %>
<% render 'message' %>
_message.html.erb
<% form_for #message, :url => messages_create_path do |f| %>
<% f.hidden_field :from, value: current_user.id %>
<% f.hidden_field :to, value: #user.id %>
<% f.text_area :message %><br />
<% f.submit "Send Message" %>
<% end %>
To make your form_for code block to render you need to use <%= tag as follows:
<%= form_for #message, :url => messages_create_path do |f| %>
<% f.hidden_field :from, value: current_user.id %>
<% f.hidden_field :to, value: #user.id %>
<% f.text_area :message %><br />
<% f.submit "Send Message" %>
<% end %>
To elaborate on vinodadhikary's answer, ERB has output tags and evaluation tags. To evaluate something you would use <% expression %>, and to output you would use <%= output.me %>. The earlier is usually used for flow control in templates, and outputs nothing. The output happens within after a decision is made. The latter is used to output stuff.

How to hide the form elements if the field is empty in ruby on rails?

I am using OpenStruct form for in my view like the following,
<%= form_for(OpenStruct.new(params[:f]), as: :f, url: product_types_path, method: :get, remote: true, html: {class: 'type'}) do |f| %>
<div class="field">
<%= f.label :product_type_id %>
<%= foreign_key(f, :product_type_id, Asset::Product::Type) %>
</div>
<% end %>
I want to hide the other form elements if product_type_id is nil or blank or empty?
I tried this,
<% unless product_type_id.blank? %>
<div class="field">
<%= render 'form' %>
</div>
<% else %>
<p>Select Product Type</p>
<% end %>
So if I got it right what you want to do is not to render the form if what you received with the param product_type_id is blank.
Is it possible for you to instatiate the variable in the controller instead of defining it directly in the form builder?
For instance in your controller:
def index
#product_type = OpenStruct.new(params[:f])
end
and in your view:
<% unless #product_type.product_type_id.blank? %>
<div class="field">
<%= render 'form', product_type: #product_type %>
</div>
<% else %>
<p>Select Product Type</p>
<% end %>
and finally your partial:
<%= form_for(product_type), as: :f, url: product_types_path, method: :get, remote: true, html: {class: 'type'}) do |f| %>
<div class="field">
<%= f.label :product_type_id %>
<%= foreign_key(f, :product_type_id, Asset::Product::Type) %>
</div>
<% end %>

blank comment entry with rails

I'm trying to add ability to add comments to projects within a "todo" type app and have run into a problem.
I've created a project with comments before and never run into this problem, but basically rails is drawing an empty comment on the project page.
I've tried a few if statements without any luck, does anyone see my problem ?
<% #project.comments.each do |comment| %>
<div class="commentBlock"><strong><%= comment.posted_by %> says:</strong>
<%=raw comment.comment %>
<small><i class="icon-remove"></i> <%= link_to 'Delete', [comment.project, comment],:confirm => 'Are you sure?',:method => :delete %></small></div>
<% end %>
<h3>Leave a comment</h3>
<%= form_for([#project, #project.comments.build]) do |f| %>
<div class="field">
<%= f.hidden_field :posted_by, :value => current_user.username %>
</div>
<div class="field">
<%= f.label :comment %><br />
<%= f.text_area :comment, :class => "tinymce" %><%= tinymce %>
</div>
<p><%= f.submit :class => 'btn' %></p>
<% end %>
Answer was an error in my controller for Projects, referenced #comment like so:
#comment = #project.comments.build(params[:comment]) by accident!!
Changed to:
#comment = #project.comments
And all works as it should :P
thanks for your help, bad "end of the day" error right there :P

rails Insert meta data from external url into table

I have a table for storing links. I'm trying to use the pismo gem for grabbing meta data from a url, and saving that to the table.
In my link controller I have a before filter :
def pismo_grab_meta_data
doc = Pismo::Document.new("http://google.com/")
#link_title = doc.title
end
Which gets called in the new and create action. In my view I pass the instance variable in a hidden field.
<%= f.hidden_field :name, :value => #link_title %>
This works when hard code the url as a string (like the above google example), but fails when I pass it the url params, like so:
doc = Pismo::Document.new(params[:url])
Error: undefined method `gsub!' for nil:NilClass
Pretty new to rails, so I assume I'm doing something stupid here. Any help is very welcome!
<%= form_for(#link, :html => { "data-behavior" => "submit-form"}) do |f| %>
<% if #link.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#link.errors.count, "error") %>
prohibited this link from being saved:
</h2>
<ul>
<% #link.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :name, :value => #link_title %>
<div class="field urlsaver">
<%= f.label :url %><br />
<% if params[:link].present? %>
<%= f.text_field :url, :value => params[:link] %>
<% else %>
<%= f.text_field :url %>
<% end %>
</div>
<div class="actions">
<%= f.submit 'Save', :class => 'btn' %>
</div>
<% end %>
The value you are looking for should be in params[:link][:url].
Change the line to :
doc = Pismo::Document.new(params[:link][:url])

Resources