Associations in Rails

I’ve been focusing a ton on learning regex, and the results have been rewarding. I figure if I put the same energy into data modeling, I will be equally surprised with what I learn. I’m starting back at square one with a review of basic associations in Rails.

I’ll be using two Active Record resources, bunnies and carrots, and playing around with the different ways I can express possible relationships between the two, and add complexity to them. I’ll begin by demonstrating a basic belongs_to/has_many relationship between the models.

These associations would look something like this in the database:

IMG_1839

In the belongs_to association, each carrot is assigned to exactly one bunny. To establish ownership of each carrot, we assign the bunny_id as the foreign key in the carrots table. In our Active Record model, carrot.rb, we establish the belongs to association via the following code:

But we’re not quite finished. Relationships are a two way street. In the table above, each carrot belongs to exactly one bunny. On the flipside, each rabbit can own zero or more carrots. To express this end of the relationship we must establish a “has_many” in rabbit.rb. The code looks like this:

Notice that the name of the model after has_many is pluralized in this case, which, conveniently, sounds correct. The has_many association tells our Rails application that each rabbit object can have zero or more carrots.

But what if we want each carrot to be shared among our rabbits? How would we go about expressing that relationship in Rails—where each rabbit has many carrots and each carrot has many rabbits. There are two ways to achieve this: has_many :through and has_many_and_belongs_to. I will demonstrate the has_many: through relationship because it allows you to create a model in your application that you can refer back to. has_many :through also lets you add columns to your join table. For a discussion on both options, see the Rails documentation on Associations.

Before generating the models in rails, let’s draw out the relationship we want to create.

photo

We want to link our two tables in a new model/join table.

In the terminal we generate our models and migrations via..

rails g model carrot color:string
rails g model bunny name:string
rails g model community carrot_id:integer bunny_id:integer

Next we must re-establish our associations between carrots and bunnies via the new community model, back in carrot.rb, bunny.rb and community.rb:

The join table/model community.rb is at the center or carrots and rabbits. community.rb binds carrots to rabbits, and rabbits to carrots. After we run our migrations, this powerful new middleman will let us use Active Record Association methods to streamline access to our data. Our migrations look like this:

We run the migrations via rake db:migrate.

So let’s open the rails console and start to examine the power of the affinity we created between bunnies and carrots. We now have access to carrots via bunnies and bunnies via carrots.

Now let’s assign another bunny to a carrot. We’ll use the method find_by to locate the bunny Hakeem in the database.

The carrot with ID #9 is now bound to two bunnies, Jasper and Hakeem. Our has_many :through association allows us to access those buns from the carrot!

Use regex lookaheads to validate a password in JavaScript.

The following problem is borrowed from Codewars, an amazing space to practice problem solving and compare solutions across languages. The challenge is to create a password validator in JavaScript using regex that returns true if a password meets requirements, and false otherwise.

To return true, a password must pass the following tests:

  • At least six characters long
  • At least one lowercase letter
  • At least one uppercase letter
  • At least one digit from 0-9
  • Contain only alphanumeric characters

Let’s build the easy part first.  We know that a password can only contain alphanumeric characters. To select from a range of characters in regex, we wrap the range within brackets like this:

[a-zA-Z0-9]

This range includes all uppercase and lowercase chars, plus any single digit between 0 and 9, i.e., all alphanumeric characters.

Next let’s filter for for matches with at least 6 characters. We express this in our regex by using a quantifier directly after the range of characters.

[a-zA-Z0-9]{6,}

The curly braces signify a quantifier in regex. The “6” is the minimum value of the quantifier. The comma after it tells the regex engine that our max is open-ended. In other words, we are telling the regex engine to match any string of alphanumeric characters that is 6 or more characters long. We could put a limit on the max by writing {6,10}, where 10 is the maximum number of characters, but in this case, we want the quantifier to be extra greedy and match very long passwords, too.

<h2>Use lookaheads to match specific conditions</h2>

Now for the tricky part. Each match must include at least one lowercase char, one uppercase char, and one digit between 0-9. We can test for these conditions in our open-ended range using lookaheads. Let’s start by testing for one lowercase char.

Image

The lookahead is expressed by (?=[a-z]) and tells the regex engine that for anything that immediately follows the lookahead–in this case, a range of at least 6 alphanumeric characters–find at least one single lowercase letter from a to z. The regex engine does just that. But there is a problem with this regex. The regex engine skips any uppercase or numeric characters that come before a lowercase character. It won’t start matching until it finds the first lower case character. We have to give the lookahead a little more breathing room. We can do this by inserting a dot, . before the character class we are searching for, which stands for any single alphanumeric character, plus underscores.

Screen Shot 2014-02-06 at 2.35.54 PM

Now the regex return a match with one uppercase character before the lowercase character. But we want both. To get more than, we’ll use the *, or asterisk quantifier, which means match zero or more of the preceding character, in this case, the dot (any single alphanumeric character). The * quantifier is the same as {0,}. In sum, we are telling the regex engine to match with at least one lowercase character, but it’s okay if the lowercase character is preceded by other characters.

Screen Shot 2014-02-06 at 2.36.09 PM

Our new regex (?=.*[a-z])[a-zA-Z0-9]{6,} still mandates at least one lowercase char, but when it looks ahead, it knows that the lowercase character can have other characters living behind it. For a full discussion of quantifiers in regex, check out this tutorial.

At this point, we’ve met the first lookahead condition, but must satisfy two more:

  • At least one uppercase letter
  • At least one digit from 0-9

To match these conditions we’ll nearly the same lookahead syntax as before.

  • (?=.*[A-Z])
  • (?=.*[0-9])

The first lookahead tells the regex engine to find at least one uppercase character in the range that directly follows; the second, at least one digit. Both regexes take advantage of the .* to tell the regex engine that the lookahead can be preceded by zero or more of any single character.

Once we combine all the lookaheads together, we have now every condition to validate a password! Let’s check it out by using the .test method in JavaScript
. The .test method is called on a regex and takes a string as an argument. If the regex can find a match in the string, .test return true; if not, false.

Check it out! When we combine all the lookaheads with the range of alphanumeric characters, .test will return true for every password that meets our five conditions. To learn more about using regex in Javascript, try solving your own reg kata on Codewars.