Rails nil errors - any way to stop them? - ruby-on-rails-3

I've been learning Rails for the past 6 months. I think it's great!
But, 99% of errors my app gets are nil errors. I'm either trying to display a field that is nil or a foreign key is pointing to a record that has been deleted.
I have this type of code in many places:
<% if location.parent != nil %>
<td><%= location.parent.name %></td>
<% else %>
<td></td>
<% end %>
<% if location.client_id != nil %>
<td><%= location.client.client_name %></td>
<% else %>
<td></td>
<% end %>
I really wish Rails would just show a blank when the field is nil! Or, set a flash with an error and still show the page. Instead, the page bombs. On Heroku, you get the "Sorry, somethings wrong...."
Is there any way to better handle blank fields? Is there a better way to code the above? Is there some Rails setting I'm not aware of? Is there a gem to handle these type of errors?

You should really place some foreign key constraints and after_destroy methods on your associations. This will stop your database getting into a inconsistant state.
But aside from that refactor you should checkout ActiveSupport and the various additions it makes to ruby. See http://guides.rubyonrails.org/active_support_core_extensions.html.
There are three methods which are available on any object which I think would be helpful to you:
blank? - Returns true if the object is nil, empty?, false and other conditions. See the documentation for a better explanation.
present? - Returns true if the object is not nil, not empty? or true. See the documentation for a better explanation.
try(:foo) - Attempts to call the method foo on the object, returns nil if the object is nil. See the documentation for a better explanation.
With this your sample code could be:
<td><%= location.parent.try(:name) %></td>
<td><%= location.parent.try(:client_name) %></td>
I would really recommend that you have a look at why you are expecting an object to not be nil. Foreign key constraints in your migration and after_destroy hooks for your associations will help with this.

Not a Rails fix, but you can use the NullObject pattern of object oriented design to refactor your code to handle "nil" differently. The pattern basically means that you create a null/nil class for an object that handles when it is nil. It has some downsides: an extra class to maintain and you have to remember to edit the null class when you add new methods which may be nil. The good is that it moves the conditionals out of the view.
Here's a good blog post on the subject:
http://robots.thoughtbot.com/post/20907555103/rails-refactoring-example-introduce-null-object
Another suggestion would be to move the conditionals out of your view and into helpers. Helpers are simple modules that contain view logic. I've suffered through views with all their logic in the view and it makes the view code a mess very quickly.

Related

Rails 3.1 simple_form renaming fields w/o i18n

I've been starting to use simple_form in my rails application, which is quite nice. But I was not able to find a function which allows me to rename a field, without the use of i18n.
I have a radio button in my formular, which allows to choose the delivery type. Controlled by that a few fields need a different naming (but its still the same field with the same information).
(e.g. there's a delivery note which is called weight note or notification depending on the delivery type, but contains the same information).
I checked the readme, the railscast and searched a lot but didn't find a build-in way to do that. One option of course would be to create a special locales file just for that, but that feels a little over the top.
I found my answer in a different question regarding simple_form. After looking for that part in the readme, I also found it there.
<%= simple_form_for #user do |f| %>
<%= f.input :username, :label => 'Whatever name you want..' %>
<% end %>
This also overwrites the name given in the i18n file.

Thinking Sphinx Global Search All Models

I'm running sphinx, thinking sphinx and have a basic ordering system with companies, users, order, notes, comments amongst others.
TS is running fine, searching in individual models and their nested resources is working brilliant.
What I wanted to do is have a global search form in my header (application.html.erb). The problem is where my form's posting to.
<%= form_tag companies_path, :method => 'get', :id => "companies_search" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
Obviously this works for my companies and nested resources. If I put it in my header, any result will be returned on my company layout.
Is it possible to create a dynamic alternative to companies_path?
Or, should I create some special layout?
What does everyone else do here?
I'd create a separate action for handling global searches - or at least, separate routing back to a reusable search action, and have that action detect whether it's a global search, company search, etc.
As for the header - do you always want it global? Because that's easy enough - just use the global/generic search action for the form constantly. If you want it done dynamically, though - defaulting to the context of the models if appropriate? - I'd probably opt for a content_for block, and add the appropriate search form in each of the relevant views.
Of course, that gets messy, so a different way could be to just customise the url via a helper that looks at params[:controller] to see what the current context is. No idea how fragile this might get, though.

Rails 3 - avoid duplication of controller code that generates a partial used in views generated by several other controllers

This is a noob question. My applets_controller has partials that will be called from views associated with other controllers.
(e.g. applets_controller _applet1.html.erb called from user_home_controller show.html.erb)
my link in show.html.erb is:
<%= render :partial => "applets/applet1" %>
I would prefer not to duplicate code to get variables from the applets_controller in all of the controllers of the views that will call the applet. How can i avoid doing this? I suppose i could transfer much of the code to the application_controller or to models. Is there a simpler solution?
Thanks.
I think you could put the relevant code & output into a Helper, and change your calls in the partial (_applet1.html.erb) to refer to that helper. That way, it would be available anywhere in your application. Depending on which helper you put it into, you may have to include a line to include AppletHelper or something similar.

rails3 authlogic-connect unknown attribute: oauth_provider

I'm trying to use the authlogic-connect plugin to add oauth support to my web app but I'm getting the error:
unknown attribute: oauth_provider
when UsersController#create is called. It is failing when I try to create a new user from the parameters that are being passed in:
#user = User.new(params[:user])
Sure enough, the parameters include this attribute:
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"lHX2BTFTd5xITTfY/X8A9R3vca3YaRuHFoWdqy8ZPik=",
"user"=>{"oauth_provider"=>"linkedin"},
"commit"=>"LinkIn"}
From the documentation, I assumed that this was what you are supposed to do:
Second, if you are using Oauth, you must include an input with name oauth_provider
and value twitter or whatever other provider you might want (see example apps for
dynamic example).
Any ideas on how this is supposed to work? All of the example forms are in yaml - which I don't know - and I'm trying to create this from using embedded ruby code. Here's the form that I'm using:
<!-- authlogic-connect hack -->
<%= form_for #user do |f| %>
<%= f.radio_button(:oauth_provider, "linkedin") %>
<%= f.label(:oauth_provider_linkedin, "Link In Fool") %>
<%= f.submit :value => "LinkIn" %>
<% end %>
As Dimitry pointed out, the best answer to this question is to use devise + omniauth instead of trying to get authlogic to work. Authlogic simply doesn't support rails3. I spent at least a week trying to get authlogic to work the way I wanted and I never solved the problem. I then spent a few hours getting devise + omniauth to do exactly what I want (i.e. you can create an account with LinkedIn or on the sight and you can associate them together so that you can login with LinkedIn or with email and password to the same account).

Rails login partial in different controller

Hey,
I'm pretty new to rails and for learning effect, I try to implement my own authorization system.
Right now I'm having a Page Controller to control some static pages and nothing more, and a Session Controller where I plan to implement most of the authorization process.
My problem is, I have no clue how to get my partial to use the sessions-controller, when I add it to one of the static pages controlled by the pages controller.
It stated out with this http://ruby.railstutorial.org/chapters/sign-in-sign-out#top but i don't want it on an extra page.
so I tried setting the routes and I got an exception "no path found for '/'" as soon as I deleted "resources :sessions" it worked fine again.
my partial looks like this:
<%= form_for(User.new) do |f| %>
<%= f.submit "Login" %>
<% end %>
there's also a div class="action" block around the submit but can't find out how to escape it
this is included into my home via
<%= render 'sessions/new' %>
Thanks for your help
edit my solution:
I added to routes.rb:
resources :sessions
Furthermore I changed form_for(#user) to
<%= form_for(:session, url => sessions_path)
so this works.
I Highly recommed that you look at the railscast http://railscasts.com/episodes/250-authentication-from-scratch , it will give you an idea how to create authentication without forgetting some important steps.
Then you can use the gem devise which is an excellent authentication gem.
Have you tried putting your functions and everything for authentication within a Session Helpers file? Then, in your Application Controller if you add "include SessionsHelper" this should give you access to all the helper functions from Session that you should need