Friday, April 25, 2008

DRY Up Your Views With Layouts For Your Partials

I got comments on my previous post, DRY up your views with nested partials, letting me know that there is a better way. So here is the same thing, done the proper way:


First, I've got this cool set of divs that gives me a nice looking window I will be reusing:


 
<div id="window-top"></div>
<div id="window">
<%= render :partial => 'mypartial' %>
</div>
<div id="window-bottom"></div>

<div id="window-top"></div>
<div id="window">
<%= render :partial => 'myotherpartial' %>
</div>
<div id="window-bottom"></div>

The goal here is to be able to re-use the code for the window multiple times. First, lets create a partial called '_lorem.html.erb':



<p>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum." </p>

And another called '_blah.html.erb':



<p>blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah </p>


Alright! Now, make one last partial, which will be used for the layout, called '_window.html.erb'. Note that it needs to be created in the same directory as the other partials. This is where you put the code for the cool window you just made.



<div id="window-container">
<div id="window-top-left"></div><div id="window-top">Window Title</div>
<div id="window-top-right"></div>
<div id="window">
<%= yield %>
</div>
<div id="window-bottom-left"></div><div id="window-bottom">
</div><div id="window-bottom-right"></div>
</div>

And now, when you want to render a partial that is inside your window, all you need to do is set the layout to window:



<h1>Test of nested partials</h1>

<%= render :partial => 'blah', :layout => 'window' %>

<%= render :partial => 'lorem', :layout => 'window' %>


And thats it! Enjoy DRYing up your views. Later

-Ralph



EDIT: if you use :layout => 'layouts/window', you can put '_window.html.erb' in /views/application and reuse it throughout the site.

Wednesday, April 16, 2008

DRY up your views with nested partials

NOTE: I got a couple of comments letting me know that the proper way to do this is to use a layout with your partial. Please see this post for instructions. Since making this post, I've been told the partial nesting is generally a bad idea, so use at your own risk.




Got a good one for you today that should help clean up your views and DRY things out. How many times, when building a website, do you use the same code over and over again to build this cool looking window that is re-used over and over?


 
<div id="window-top"></div>
<div id="window">
<%= render :partial => 'mypartial' %>
</div>
<div id="window-bottom"></div>

<div id="window-top"></div>
<div id="window">
<%= render :partial => 'myotherpartial' %>
</div>
<div id="window-bottom"></div>

Well, you can use nested partials to achieve the same effect and re-use your window code. First, lets create a partial called '_lorem.html.erb':



<p>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum." </p>

And another called '_blah.html.erb':



<p>blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah </p>


Alright! Now, make one last partial, '_window.html.erb'. This is where you put the code for the cool window you just made.
Inside of it, you want to render a partial, and pass in the variable 'name':



<div id="window-container">
<div id="window-top-left"></div><div id="window-top">Window Title</div>
<div id="window-top-right"></div>
<div id="window">
<%= render :partial => name %>
</div>
<div id="window-bottom-left"></div><div id="window-bottom">
</div><div id="window-bottom-right"></div>
</div>

And now, when you want to render a partial that is inside your window, all you need to do is render the 'window' partial, and as a local
variable named 'name', pass in the name of the partial you want rendered inside of it:



<h1>Test of nested partials</h1>

<%= render :partial => 'window', :locals => {:name => 'lorem' } %>

<%= render :partial => 'window', :locals => {:name => 'blah' } %>


And thats it! Enjoy DRYing up your views with nested partials. Later

-Ralph

Wednesday, April 9, 2008

ActiveScaffold - Helpers for columns with same name overwrite each other - FIX

Really quick one today. I was working on my ActiveScaffold project, and came across the following problem:
My Events table has a column called schools, and so does my Schools table. For the Events, I needed a dropdown box listing all schools...while for Schools, I needed a text box to show up to type in the name of the school. Since textboxes are the default for activescaffold, I shouldn't need to do anything with schools in it, however, when I wrote a form override for Events in event_helper.rb to give it a dropdown box...the dropdown showed up in Schools also. So first, I tried doing a form override in the school_helper.rb. No luck, the event helper method has the same name, and overrides whatever method I put in school with the same name. So to fix it, I removed my helper methods from the event and school helpers. In application_helper.rb, I made a function with the same name as the form override function I had been trying to use, and then used an if to determine which model the helper was being called from. Here is the code:


# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper

#hack to make activescaffold form overrides work when 2 models have a field that is the same name
def school_form_column(record, input_name)
if record.class.name == "Event"
select_tag input_name, options_for_select(aschools, selected = record.school)
else #record.class.name =="School"
text_field :record, :school, :name => input_name
end
end

private
#used in case of Event
def aschools
@schools = School.find(:all, :order => 'school')
@schooloptions = Hash.new
for school in @schools
@schooloptions[school.school] = school.abbrv
end
@schooloptions = @schooloptions.sort.each { |e| puts "#{e[0]} => #{e[1]}" }

end

end



Me: 2
ActiveScaffold: 0

Done.

Wednesday, April 2, 2008

Rails 2.0 Links

Decided to make a post with links to all the good resources I have come across so far. I'll be putting a permanent link to it on the sidebar. Feel free to leave a comment if you have any links you would like me to add.


RubyPlus.org - Lots of good screencasts; Restful Authentication, AWDR's Depot app for Rails 2.0


Rails Envy - They have a great ActiveRecord intro video here, among other things


Railscasts - Should need no introduction :)


Planet Ruby on Rails - Has feeds from many different Rails blogs all in one convenient place


InstantRails - For you Windows users, this program is a quick way to get up and going with Rails


DanielFischer.comTutorial for using Gmail as a mail server for a Rails project.


Jonathan s ng - ActionMailer Tutorial


Render Examples - Great render examples, helps when needing to render things with AJAX


Absolute Moron's Guide to Forms in Rails - Great form tutorial



Will be adding many more links in the days to come, this is just a preliminary list. Also, I would like to get some links for setting up Rails for development on several OS's(Linux flavors, MAC, ...), so if you have any please leave a comment.


Later.

-Ralph

Tuesday, March 25, 2008

Found a nice ActiveRecord Tutorial

Wish I had found this a couple of months ago, it would have moved me along a lot. I still learned a good deal from it though.
Check it out at:


Rails Envy

-Ralph

Monday, March 24, 2008

Legacy MySQL Database - TinyInt

Apparently Rails typecasts MySQL tinyint's as booleans. I was working on a Rails app for a legacy database today when I realized that I couldn't pull the value out of my 'terms' column. All it would read is a true or false, and not the actual value. After a bit of research, I discovered before_type_cast accessor. So instead of using report.terms, in order to get the value out, I had to use report.terms_before_type_cast.


Short post, but I'm sure someone will have the same problem at some point and will find it helpful.



Later.

-Ralph

Friday, March 21, 2008

Tutorial: Beginning AJAX with Rails 2.0

Today, I'm going to go over a quick tutorial of some basic AJAX functions. Rails has a great implementation with AJAX right out of the box, with the Prototype library. It also includes the Scriptaculous library with some special effects. We are just going to do some basic writing text into the site without page reloading. Lets get started.


Set up the application:


 
rails ajaxtest -d mysql
cd ajaxtest
./script/generate model Foobar foo:string bar:string
./script/generate Controller Foobars

This is our first project that doesn't use scaffolding - I decided against it because scaffolding would have generated all kinds of views we aren't going to need for this. Notice that when you created the model, it automatically generated your DB migration file. Now, lets open up app/controllers/foobars_controller.rb and do this:



class FoobarsController < ApplicationController
def index
@foobars = Foobar.find(:all)

respond_to do |format|
format.html # index.html.erb
end
end

end

Next, create app/views/foobars/index.html.erb:



<h3>Foobars!</h3>
<table>
<tr><th>Foo</th><th>Bar</th></tr>
<% for foobar in @foobars do %>
<tr>
<td><%= foobar.foo %></td>
<td><%= foobar.bar %></td>
</tr>
<% end %>
</table>

Now lets add our routing. In config/routes.rb add:


  map.resources :foobars

In your console, lets get our db created and foobars table setup:



rake db:create
rake db:migrate

And one last thing. We need to populate our table with a few foobars. This is a good time to show you the rails interactive console:


./script/console

From here, we can give commands directly to our project. Lets try one:


Foobar.find(:all)


>> Foobar.find(:all)
=> []

So it returned an empty array. The interactive console is great for playing around with bits of code to see what they do or even testing out bits of code. Lets try another command:



>> myfoobar = Foobar.new
=> #<Foobar id: nil, foo: nil, bar: nil, created_at: nil, updated_at: nil>
>>

Creates a new foobar object...



>> myfoobar.foo = "This is a test."
=> "This is a test."
>> myfoobar.bar = "This is only a test."
=> "This is only a test."
>>

We can set the values of foo and bar for our new foobar, and...



>> myfoobar.save
=> true
>>

We can save it to the database. Lets try looking it up with find...



>> Foobar.find(:all)
=> [#<Foobar id: 1, foo: "This is a test.", bar: "This is only a test.", created_at: "2008-03-21 18:24:46", updated_at: "2008-03-21 18:24:46">]
>>

Great - so far so good. Now lets create a few more foobars:



myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #2"
myfoobar.bar = "Bar of foobar #2"
myfoobar.save

myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #3"
myfoobar.bar = "Bar of foobar #3"
myfoobar.save

myfoobar = Foobar.new
myfoobar.foo = "Foo of foobar #4"
myfoobar.bar = "Bar of foobar #4"
myfoobar.save

And done. You can type exit to leave the interactive console. Start the server, browse to localhost:PORT/foobars



Tablespoon of AJAX


First thing, I'm going to tell you that if you don't have Firebug yet, go ahead and get it. It is a plugin for Firefox(you are using firefox, right? nothing against you Safari/Opera lovers..if you are using IE you have no excuses, get Firefox and get Firebug...now). Firebug is a great tool for design as well as for AJAX. The inspect mode will highlight divs under your mouse and show the corresponding html/css code in the panel below. You can also take a look at Javascript AJAX responses and more quickly debug your code. Lets create app/views/layouts/application.html.erb:



<html>
<head>
<%= javascript_include_tag :defaults %>
</head>
<body>
<%= yield :layout %>
</body>
</html>

The include tag will include (among other things) the prototype library that you need to make the AJAX calls. Now, lets head back to app/views/foobars/index.html.erb and set it up for our AJAX. Change it to this:



<h3>Foobars!</h3>
<table>
<tr>
<th>Foo</th>
<th>Bar</th>
<th>Which?</th>
<th>Links</th>
</tr>
<% for foobar in @foobars do %>
<% idstring = "foobar-" + foobar.id.to_s %>
<tr>
<td><%= foobar.foo %></td>
<td><%= foobar.bar %></td>
<td id="<%= idstring %>"></td>
<td>
<%= link_to_remote "Foo", :url =>{ :action => :set, :updatewith => foobar.foo },
:update => idstring %>
  
<%= link_to_remote "Bar", :url =>{ :action => :set, :updatewith => foobar.bar },
:update => idstring %>
</td>
</tr>
<% end %>
</table>

We have 2 more columns in our table now - Which? will be updated by AJAX with either the foo or the bar of our current Foobar depending on the link clicked from the Links column. In the Links column, we have 2 link_to_remote 's. link_to_remote generates all the javascript calls to send an AJAX request back to our controller on the server. The first argument is what will be displayed for the link. In :url, we define the action to send the request to (:set), as well as the string we want to pass into the function (:updatewith). Last, :update will be the name of the div we will be updating. You can also add another parameter, :position. For example, :position => :before would insert whatever you are sending before the td tag, :after would be after it, :top would insert it inside the td, above anything else, and :bottom inserts it inside the td, at the bottom. If you do not specify a position(like we are doing), it will simply over-write what is inside the div. One more thing to do; lets open up app/controllers/foobars_controller.rb and add in our :set action:



def set
render :text => params[:updatewith]
end

Go back to the page and try clicking the links



Update: I found this link to be very helpful with different ways of using render with AJAX.



And we are done! Thanks for visiting, and see you next time.