SyntaxHighlighter

Sunday, December 24, 2006

Redirecting to HTTPS in Rails

There are a couple simple steps to take to secure your login pages with rails. First, you'll need a certificate - this I got through my ISP, so I don't have much insight into this. It was uneventful and worked right away.

Once you have the certificate and HTTPS works for your site, you'll need a before filter on any pages that should be https and another one to send all other pages to http. For example:

before_filter :require_https, :only => [:login, :signup, :change_password] before_filter :require_http, :except => [:login, :signup, :change_password]

def require_https
redirect_to :protocol => "https://" unless (@request.ssl? or local_request?)
end

def require_http
redirect_to :protocol => "http://" if (@request.ssl?)
end

This will put any pages that should be HTTPS in the right protocol.

And, if you have a login form on an HTTP page (this may be on the home page of a sight), you'll need the form action to point to the https version of the form. To do this, set the "start_form_tag" helper like so:

<%= start_form_tag({:protocol => 'https://', :controller => 'user', :action=> "login", :only_path=> false}) %>

This is necessary to set the protocol to https. Note, the "only_path" value is set to "false". This is because "only_path" defaults to true and will ignore the protocol unless it is set to false.

Sunday, November 26, 2006

Grovr.com

I've been messing around with Ruby and decided to update my content manager by implementing it in Ruby. This gave me the chance to add a whole host of new features and refine a few things.

The new site is called Grovr and your welcome to try it out. It's not even "alpha" in the sense I don't plan on opening it up to the public officially, but it is available to use and registration is free and open.

Tuesday, September 26, 2006

Containing floating elements

A common problem with using XHTML and avoiding tables - containing the floating left and right elements on the page so the parent element completely wraps the children. If you are making a left nav, using a < id="leftnav"> approach, you've probably struggled with this at some point.

Here is a great article by Ed Eliot explaining a few strategies for fixing this.

http://www.ejeliot.com/blog/59

Monday, September 25, 2006

Document.getElementById Bug/Problem

The getElementById method is supposed to return the first element in the document with the specified id. See the spec. There is a bug in IE (perhaps it's intentional), that will return an element with the name, instead of the id.

Try out the following. Get element by ID and display it's ID. You'd think it would be the same id that was just asked for, in this case 'child'...

< type="checkbox" onclick="alert('child = ' + document.getElementById('child').id)">
< type="hidden" name="child" id="hidden_child">
< type="checkbox" id="child">



To work around this - make sure you keep id's unique to each other and to elements that are named. Or be sure the id elements are found first, in document order.

Sunday, September 24, 2006

Ruby file upload

OK - An update. I got a suggestion from a friend (after my upload post) to try file_column. I tried it and it almost worked perfectly. Much nicer for my uses.

The one problem - the files are stored in directory per image_id - one image per directory. This was overkill for my needs, I wanted to store the images in a directory per project_id. To do this, I had to make some manual changes to file_column.rb and my environment.rb files. I'll do my best to post what I did here...

On lines 359 and 361 in file_column.rb, the original code would delete an existing directory and move over the temporary directory to replace it (after a successful download). I modified it to simply move the file over, make the directory if it needs to.

FileUtils.mkpath(@dir) unless File.exists?(@dir)
FileUtils.mv File.join(local_dir, @filename), File.join(@dir, @filename)

On line 395 the code deletes the directory, you must change the delete_files method to be

FileUtils.rm_rf File.join(@dir, @filename)

So only the particular file is deleted.

In my environment.rb file, I overrode the ___ method so the directory name would be based on the user's project.

require 'file_column'
require 'file_column_helper'
require 'rails_file_column'

module FileColumn
class PermanentUploadedFile

def relative_path_prefix
project = Project.find(@instance.project_id)
"#{project.name}"
end

end
end

Thursday, September 14, 2006

Beatstreet

Here's a product idea for you.

Beatstreet - A music player for runners where they can control the tempo

How about a mp3 like player (it would play midi files primarily) that has the ability to change tempo. The midi tunes would play for as long as the runner wants. Ideally, it would change rhythm upon request, but seemlessly integrate it with the current beat.

I call them 'rhythms' as they would be very repetitive and motivating, like a good Moby song or dance beat.

Research shows runners reach their best times listening to music they enjoy. What about music that increases their rhythm?

As Ethan Lowry points out, if Nike's new ipod included this feature, it "would be incredibly cool".

Wednesday, September 13, 2006

Ruby file upload

Uploading files in Ruby took a little time - I was mainly hung up on the File and Directory management. But, after a little trial and error on my part, here's the result. Comments are welcome, as I'd like to improve it...

Some notes - I wanted to store the images in a custom directory under /resources. The resouce model object has a 'path' and a 'title' property.

def self.new_from_upload (upload, directory)
file_name = upload.original_filename
dir_path = "#{RAILS_ROOT}/public/resources/#{directory}"
file_path = "#{dir_path}/#{file_name}"
resource_path = "/resources/#{directory}/#{file_name}"
file_name.chomp!(" ") # remove spaces on the ends


if file_name.length > 0
data = upload.read
# Delete file if it exists

delete_file_if_present file_path

# Write new file
create_dir_if_missing dir_path
File.open(file_path, "wb") do
f f.write(data)
end

resource = Resource.new
resource.title = file_name
resource.path = resource_path
return resource
end
end

private
def self.create_dir_if_missing name
Dir.mkdir(name) unless File.directory?(name)
end

def self.delete_file_if_present file_path
File.delete(file_path) unless !File.exists?(file_path)
end

This creates the directory and the file (if missing). Overwriting the file when it's uploaded again.

One improvement that is coming - I'm going to store the file in a temporary directory until it is uploaded. Once in place - I'll move it over and update the model object.

Saturday, September 02, 2006

Google Code

I've been trying to find a server to host a project I am working on. I didn't want to pay for an ISP and I was willing to make the project Open Source. The project was originally going to be in Java, so I tried to get on tigris.org, or sourceforge.net. Both turned me down (well, tigris didn't reply). I finally got on to java.net (the projects name is 'poster'), but that was more than I needed and CVS was required for source control. I was hoping to use SVN.

I recently discovered Google Code and this is perfect for my needs. It uses SVN, has a very simple issue tracker, and makes it very easy to select an open source license. So far so good.

Sunday, July 30, 2006

CSS Inheritance Rules

Web development has a number of technolgies that can be used to render a web page. Here's the most important one's for me:
  • HTML
  • CSS
  • Javascript and DHTML
  • Ajax (Using Javascript to make server requests and update portions of the page).
  • Some scripting language - JSP, XSLT, ASP.Net, PHP
  • Flash
CSS is a very important peice in this list of technologies to master, but one most front-end developers think is simple and one that can be ignored or cut-and-pasted. I have a couple interview questions that I ask about CSS and as yet, no one has been able to answer them correctly and confidently. Developers tend to "get by" with css. This is often true with javascript, too.

I mainly want to know if the interviewee knows how cascading works in CSS. Specifically, I ask:
"Can you give me the formula for determining how a style rule is applied to an element when there are multiple rules that could apply?"

Or in CSS vernacular -

"How do you calculate a selectors specificity?" The answer is here

This isn't critical to being hired, but understanding the algorithms used by browsers to handle rule conflicts in CSS will only help your web development and shows you have a handle on this area of web development. Of course, using CSS in a practical way requires a deeper knowledge of the actual declaration properties that can be applied to the HTML elements. This just comes with time and experience.

Tuesday, July 25, 2006

Reusing JSTL tags

We're using jsp and tag libraries pretty heavily in the enterprise application at Jobster. I had a chance to rewrite the application front-end code a few months ago, and came away with an infrastructure and architecture that is pretty nice for reusing components and 'widgets' on the front end.

For example, the list of jobs, and the list of prospects might have many similarities in HTML and CSS. Having these two pages use the same tag to render the parts that are similar is a win - reducing code, making it easier to maintain and update.

In our case, we have many lists (recruiters, prospects, contacts, employees, jobs, sources, messages to name a few) that have similarities.

I ended up with a mini-MVC architecture in the tag libraries. Where some tags took on Model properties, some took on Controller properties, and some acted more like Views.

The model type tags were needed to get the data in a very predictable consistent format. Lists of Maps was the preferred approach. If the data for one job list was slightly different than another job list, I used the model tags to convert and standardize. If I was handed a list of "Job" objects, I would convert to lists and maps.

The controller tags were application/use specific - they were used to combine the right data with the right view. For example, the recruiter list and the contact list are both lists of people, but they displayed different properties for each person in the list. The controller tag in this case accepts the data for the recruiter (a java.util.List object), calls the correct table row tag for each item in the list to generate the recruiter specific row, and passes these results to the view tag for final rendering.

The view tags are application agnostic. They accept strings and output them. This is a nice split, as the view tags can be reused easily. CSS becomes the only way to create different looks, the HTML is always consistent and predictable. There are view tags for the different parts of the page. Each is a wrapper that may include the results of another tag.

Most of my tags ended up being controller tags. Most of the changes occur in Layout tags. Code size reduced by 25%. Page weight reduced by 50%.

Once this infrastructure was in place, we were able to go through a complete redesign of 230 screens in the recruiter enterprise application - implementing a new brand in about 5 days (front-end coding). Most of modification occured in the wrapper view tags, and the CSS files. Past redesigns would take significantly longer.

Monday, June 12, 2006

Maxwidth, Minwidth

To set the maximum width and minimum width of a block item, you can do a combination of things. Mozilla understands "max-width" and "min-width" css rules. Unfortunately, IE does not, but IE does give you another, very powerful option. Expressions in CSS allow you to do all sorts of things with javascript, the dom, and css styles.

Here's how one would set the width of an element in the page.

.mainwidth{
max-width:1024px;
min-width:800px;
width:expression(document.body.clientWidth > 1024? "1024px": (document.body.clientWidth < 800? "790px" : "auto")) };

Note - I had to set the size to be a few pixels larger than the campared width (800px). Otherwise, IE would crash.


Looking online, this is apparently due to a missing doctype declaration. My page was set to:

http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd

It was not immediately obvious why this error would occur, but it was not enough to warrent greater investigation at this time.

After adding this to the style sheet, the user can resize the page. The items in the page will hold their minimum and maximum widths appropriately.

This was checked on IE6 and Mozilla 1.5.

Sunday, June 04, 2006

Starting with Ruby

I started messing around with Ruby a few weeks ago to learn more about the technology. I now have about 30 hours of experience and am sold on it. A person can accomplish a lot with Ruby in a short time. It seems to be ideal for the front-end developer, as more back-end coding is easier to handle - such as creating the database model, or writing the business logic.

Having a background in jsp, spring framework, MVC frameworks, and ajax helps give some understanding to the conventions used in Ruby and Rails.

Looking forward to doing more.