Archive | March, 2013

Rails E-Z Authentication 1-2-3

30 Mar

I’ve been long considering a way to put some restrictions on the Target Cancer site to keep casual onlookers of the Home page from mucking about and stepping on things Backstage.

For those who aren’t already in the know, the Target Cancer site is an experimental site I’m making for a friend who is doing a benefit concert with a bunch of musician friends from the Pharma industry. I wanted to create a site where they could advertise the event, provide directions, performer bios and so on, and then also have a back-stage area where the performers could collaborate via a Forum page and an editable list of Songs with lyrics, chords and links to youtube videos (most if not all of the songs are covers in this case).

I was hesitant to implement a full-blown user authentication system on the site, however, because high security isn’t the issue here, and as exciting as it might be to implement, I don’t want all sorts of user registration rigamarole getting in the way of helping these busy people to get together (virtually speaking) and collaborate on their collective goal of learning a bunch of songs, discussing them and keeping track of who’s playing which song.

So with a bit of searching I found my first clue. Someone pointed the way to a Railscast video which showed (almost) exactly what I was looking for:

http_basic_authenticate_with :name => "frodo", :password => "thering"

Putting the line above in the controller who’s views you wish to hide from casual view works great, and there are way you can hide the username and password from the code as well if you wish, such as putting it in an external config file.

But I had a bunch of controllers and views I wanted to hide, and putting that line at the top of each controller would mean (I think, I didn’t actually try it to be honest) back-stage users having to enter a password several times as they traversed the different controllers for Songs, Posts, Users and so on.

So I searched a bit more and found exactly what I was looking for. Here’s how it’s done.

First, create a new ‘Admin’ controller. Call it what you like, but ‘Admin’ is as good a name as any!

rails g controller Admin

Now edit that controller to look like the following, putting in your own values for the username and password:

class AdminController < ApplicationController
  before_filter :authenticate

  def authenticate
    authenticate_or_request_with_http_basic
        do |username, password|
      username == 'admin' && password == 'password'
    end
  end
end

Great. But what about authenticating all the other controllers? Here’s how:

For each controller you want protected change the top line to inherit from AdminController instead of ApplicationController.

For example:

class PostsController < AdminController
  layout 'backstage'
.
.
.

It’s that simple!

AdminController already inherits from ApplicationController for them, so all they’re getting is a little extra, specifically the before_filter and the authenticate method. By inheriting this code, the authentication applies to them all without the user having to manually type a log in for each one.

You can go backstage at the Target Cancer site if you wish with the following login:

performer / pass4backstage

Just try not to step on anything! (If you do, just leave some beer in the fridge by the pool table and all is forgiven.)

;)

Rails 3 Many to Many

28 Mar

Working on the Target Cancer site has given me a pretty good grip on creating 1-to-many relationships in rails. For each Song there are many comments and likewise for each Post.

I then wanted to add some functionality to allow for Users to be entered and for those users to be able to choose Songs in which to Perform. Each user could perform on many songs and each song would have several users (let’s call them Players) performing them.

That much I was able to visualize clearly, but actually putting that into Rails terms was fairly intimidating, and after a few sketches and some fits and starts, I finally had to start doing some hard research as to how, exactly, this would be implemented.

So I created a simple Rails app in which to model this relationship exclusively. I also found some good tutorials to get the models and migrations sorted out, my favorite of which can be seen here.

In order to give the Songs and Player models access to each other in a many-to-many fashion I chose to go the route (no pun intended) of has_many :through which, if you’ve read a bit on Rails relationships, you’ll know is a more flexible alternative to the method using has_and_belongs_to_many. The ‘has_many’ route involves building a 3rd model to mediate between the two. Instead of just a simple table to track the foreign keys, the ‘has_many’ approach lets you add columns to the table in addition to the foreign keys, which can be very useful for tracking information that relates to the relationship, if that doesn’t sound too strange. I put a ‘role’ column in there, and called the new model ‘Performances’, the purpose of ‘role’ being to store the role a given Player would play in the performance. So Player ‘John Doe‘ might have a Performance role of ‘bass and vocals’, While ‘Billy Zoom‘ may have the role of ‘blazing rhythm and lead guitar’.

So the tutorials got the ball rolling, but then left me still pretty clueless as to how to manipulate these objects usefully in my own application. Testing in the rails console, I found that I could quite easily add a Player object (selected using Player.find(:id)) to a song (selected in the same fashion) simply by doing the following:

song << player

I thought that was pretty neat, but then found it difficult to update the role which the give Player was playing in that song. Using the method above, the role remained ‘nil’.

After quite a bit of fumbling, I finally resolved to contact the Boston Ruby Group for assistance. My hat is off because the response time and detail with these folks is PHENOMENAL! One kind user clued me into the following:

song.performances.create(player: player, role:"guitar")

All in one line, save to the database and everything! This began to shed light on another problem I was having, which was getting Song and their associated Players (and roles) to display nicely on a view. I was trying the following code and getting errors:

<% @songs.each do |song| %>

      <%= song.title %><br/>
        <% for i in 1..song.players.length %>
          <%= song.players[i].name %>, 
          <%= song.performances[i].role %>
        <% end %>
      <% end %>

This was resulting in a “undefined method `name’ for nil:NilClass” error, and I knew in any case that my approach was wrong and there had to be an easier way. Sure enough there was, and after taking some time to digest the response I got from the BRG folks, I came up with the following:

<% @songs.each do |song| %>
      <u><%= song.title %></u><br />
      <% song.performances.each do |performance| %>
          <%= performance.player.name %> -
          <%= performance.role %><br />
      <% end %><br />
<% end %>

This spits out everything I wanted as neatly as can be:

Songs

Miserlou
Kent – guitar
John Doe – bass guitar

Louie Louie
Kent – tambourine
Sally – bazooka and lead vocal
John – drums and percussion

Love Me Do
John Doe – bass guitar and lead vocal

Happy me! Big thanks to the BRB for wisdom and guidance on this (and other soon-to-be-posted) issues. I’m amazed at how easily (once you know how) Rails lets you access all the columns in the join between the two tables, from either side (or the middle for that matter). This is still sinking in, but is a powerful lesson for me.

I don’t have the code for this on GitHub, as it’s just a sketch, but for the curious I’m putting the Model code here:


class Song < ActiveRecord::Base
  attr_accessible :title
  has_many :performances
  has_many :players, :through => :performances
end

class Player < ActiveRecord::Base
  attr_accessible :instrument, :name
  has_many :performances
  has_many :songs, :through => :performances
end

class Performance < ActiveRecord::Base
  # attr_accessible :title, :body
  attr_accessible :player, :song, :role
  belongs_to :player
  belongs_to :song
end

The schema code (Rails puts this in a single file very conveniently) is here:

ActiveRecord::Schema.define(:version => 20130328181909) do

  create_table "dogs", :force => true do |t|
    t.string   "name"
    t.integer  "age"
    t.string   "sex"
    t.string   "breed"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "performances", :force => true do |t|
    t.text     "role"
    t.integer  "player_id"
    t.integer  "song_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "players", :force => true do |t|
    t.string   "name"
    t.string   "instrument"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "songs", :force => true do |t|
    t.string   "title"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

end

Never mind that ‘Dogs’ table behind the curtain. That was for troubleshooting another issue which will appear in another post!

Happy!

19 Mar

People I DON’T KNOW are using the Target Cancer site. This is very cool!

What I mean is, the people it was intended for (a small group of musicians who need to learn a bunch of songs for an upcoming gig) are already using the app. A very interesting and good feeling!

Like writing a book and having people read it, or a song or whatever.

Still more to do!

Helpers -n- Comments

19 Mar

It took some hair-pulling (okay, a LOT of hair-pulling) but I finally got comments working on the Target Cancer site. Happiness! There’s still no user authentication, so anyone can post a comment (please bear in mind the site is actually being used already if you do any poking around – which is welcome) without having to log in or anything sensible and secure like that, but…IT WORKS!

I tried to do it all by hand at first and ran into trouble, then tore it down and did it again using scaffolding to give me a head start. Still ran into trouble, but this time I eventually got past it!

Not sure I can make sense quite yet of what the trouble was, as I am still rather at the ‘flailing’ stage as a developer when things go awry. Story of my life, really. I am getting better, though, at finding the trouble spots that matter. I remember the utter cluelessness I felt when first trying to get a grip on rails basics and, well, I’m beyond that at least!

I also wrote a very simple helper method:

module ApplicationHelper

  def commentsCount(song_id)
    count = Comment.where(song_id: song_id).size
  end

end

Hey, I told you it was simple didn’t I? I use it to get a count of the comments for a particular song so that the comments link can have the current number of comments for that song in parens next to it. Works great!

Website updates

18 Mar

I don’t think I’ve ever been this productive in a coffee shop setting before, but this morning the fires o’ creativity were well-stoked indeed!

I’ve applied a fair amount of the changes specified in the previous post to the Target Cancer site. New header and footer, links (many just dummy for now) and other tidbits. I created a Comments controller which I don’t think was necessary, as there’s no CRUD happening there, but I’m keeping it for now.

Still no Comments or user authentication, but that will come.

Check it out here (but please don’t add or edit songs ; ).

Code is on GitHub under the name danjam.

Target Cancer Jam site design sketch

18 Mar

Diary of a Madman

My friend likes the idea of the site, so I’ve been doing a bit of brainstorming as to how best to flesh it out, and thought I’d share it just for posterity’s sake here. A work in progress, of course!



Target Cancer site (just brainstorming basic layout and objects)

objects and object notes:
Song has_and_belongs_to_many :users, set_list_position (int unique)
Performer (isAdmin?) has_many comments, has_and_belongs_to_many :songs
Comment belongs_to :performer columns: username, title, body, timestamp

————————-
layout, home page

(header)
TC Benefit Concert time & directions | contact | backstage

(body)
(splash photo/logo? and description of event)
who? (“talented member of the pharma community!”, link to player bio’s)
what? (“a kick ass rock and roll revue”)
where? (venue description)
when? (time and date info)
why? (“to benefit Target Cancer”, admission/donation info and link to TC website)

(footer)
Home | Donate to TC Now! | Time and Directions | Contact | Backstage

————————-
layout, performer login page (shows when ‘backstage’ link is clicked, unless performer is already logged in. Upon first logging in, user is redirected_to announcements page, otherwise ‘backstage’ link for logged in user goes to backstage main)

(header – same as home page)

username
password
link -> forgot password

(footer – same as home page)

(footer)

————————-
layout, comments page (shows when ‘Contact’ link is clicked

(header – same as home page)

Comments? Questions? Want to Participate?
(contact info)

(footer – same as home page)

————————-
layout, backstage-main, viewable only by logged-in performers, current number of comments is visible next to ‘comments’ link text for each song

(header)
home | backstage main | announcements | my songs

(body)
list of songs with action links for each song (chords & lyrics, play video, comments)
actions:
chords & lyrics – displays chords page with chords, lyrics and any related links
play video – opens youtube of song in new tab
comments – displays comments page for song with song title at top, comments have username, title, body and date

(footer – same as home page)

————————-

layout, comments page

(header)
home | backstage main | announcements | my songs

(body)
list of comments
actions: add comment, delete (existing, belonging to user only)

(footer – same as home page)

————————-

layout, ‘chords & lyrics’ page

(header)
home | backstage main | announcements | my songs

(body)
chords and lyrics
actions: (edit – admin only?)

(footer – same as home page)

————————-

layout, ‘my songs’ page

same as backstage main, but filtered for user’s songs only

NOTES: songs for users are assigned by Admin (Dan) only

Target Cancer site launch

15 Mar

I’m cobbling together a simple Rails site for a friend who is organizing a concert in support of Target Cancer.

Everyone in the band will have a background in the Pharma field. My wife, a scientist at EMD Serono, will be playing drums!

The site is functional now but totally bare-bones. It lets users add song titles and URL’s (mostly from YouTube), as well as comments which could include anything from “I hate this song” to chords, lyrics or what-have-you. I have lots of ideas for further functionality and layout for the site, so hopefully it should be blossoming further in days to come. Just in time for Spring!

Check out the site HERE.

Caveat: Please understand, it’s really just a functional sketch at this point!