Using Hashes in Ruby on Rails

This week has really highlighted to me the importance of knowing how to figure out the way in which to access data created in one part of an application from a different part of an application. Something that has helped me with this has been to brush up on my understanding of how hashes in Ruby work, and how this can be used to send and receive data in Rails.

What is a hash?

When writing a program you will often need to store large amounts of data. This 'large amount of data' is called a collection. In Ruby a collection comes either in the form of an Array or a Hash.

Arrays and Hashes are also known as data structures.

Arrays

In an array the data is stored as an ordered list of values.

Here I will create an array called a (the stuff after the => shows what it returns):

a = [] => []

I can then add elements to the array. I kind of imagine the elements in an array as boxes. It starts at box 0 and goes up from there. When you add an element to an array you are putting something in that box. Here I will add some elements to my array called a:

a[0] = "hello"

=> "hello" a[1] = "how" => "how" a[2] = "are" => "are" a[3] = "you" => "you"

This will then mean array a contains 4 elements:

a

=> ["hello", "how", "are", "you"]

You can then pull specific bits of data out of the array. This is called 'indexing'. So if I wanted to get out the the word “are” from my array I would have to index the third element.

I would index it using a (name of the array) followed by the number at which I wanted to index inside []:

a[2]

=> "are"

I indexed the third element using the number 2 because we start counting from 0.

Data in arrays is commonly accessed via iterating over the collection. For example:

a.each do |greet|

puts greet

end

Which will print:

hello

how

are

you

=> ["hello", "how", "are", "you"]

So that is the bare minimum description of what an array is. The concepts of Arrays and Hashes are used in many programming languages, not just Ruby. In some languages Hashes are called Dictionaries. For further info on all of the things you can do with an array check out the Array Class documentation: http://www.ruby-doc.org/core-2.1.2/Array.html

If you are really new to Ruby or if you have some experience but want a refresher (like I have been doing with the Hash documentation this week) try out the examples in the documentation using irb (interactive ruby) or pry http://pryrepl.org/

Hashes

Hashes are similar to arrays in that they too are ordered collections. The difference is predominantly in how they are indexed. An array needs to be indexed with a numerical value.

In a hash, data is stored using a key and a value. To index the hash you specify the name of the key which will then return its corresponding value. A key can be any object you like, where as an array will always need to be indexed using a number.

Here is a hash I have created called person:

person = {}

person = { name: "Rosa", age: 24, city: "Brighton",
fav_colour: :purple }

=> {:name=>"Rosa", :age=>24, :city=>"Brighton", :fav_colour=>:purple}

So here name: is a key and “Rosa” is a value.

To index (get out) “Rosa” from the person hash I would use it's key:

person[:name]

which returns:

=> "Rosa"

You can also loop through a hash like so:

person = { "name" => "Rosa", :age => 24,
"city" => "brighton", :color => :purple }

=> {"name"=>"Rosa", :age=>24, "city"=>"brighton", :color=>:purple}

person.each do |key, val|

puts "#{key} is: #{val}"

end

Will print:

name is: Rosa

age is: 24

city is: brighton

color is: purple

=> {"name"=>"Rosa", :age=>24, "city"=>"brighton", :color=>:purple}

In older versions of Ruby they key is associated with the value using a slightly difference syntax (a hash rocket =>). So the person hash would be written like so:

person = { "name" => "Rosa", :age => 24, "city" => "Brighton",
:color => :purple }

=> {"name"=>"Rosa", :age=>24, "city"=>"Brighton", :color=>:purple}

and indexed:

person["name"]

=> "Rosa"

How would I know whether to use a hash or an array?

Usually both would work but a hash is generally easier to maintain especially if you have a large amount of data. This is mostly because if you have a load of data and you need to index a value, it is going to much easier to remember where it is in the collection if it is stored and found using a descriptive name. Otherwise you need to count through each element in the array until you get to the box storing the value you need which is not as reliable and takes longer. If I needed to iterate over a small collection I would probably just use an array.

As with arrays, there is a lot more depth that I could do in to. Again I would recommend playing around with the examples in the documentation using either irb or pry: http://www.ruby-doc.org/core-2.1.2/Hash.html

In this blog post I thought I would focus more on how hashes can be used in Rails, especially when working with data in a database.

The Ruby on Rails framework provides a library called Active Record which provides an abstraction for accessing databases. Rails has a number of Active Record query methods that can be used to access data from within a database.

A database is wrapped in a class; so my relational database is called accesses and is wrapped in a class called Access. Each instance of the class (defined in the @access variable in the Users controller) will make up a row in the Access database table.

Snip20140523_2

When the instantiated object is created, some data can be passed in to it, and a new row in the database (containing that data) will be born.

In order to pass in that data I have used a hash. I have not manually specified the values within my hash, but rather used values that are stored inside something called a params hash.

Snip20140523_4

To demonstrate the reason for the params hash I will show you how I would manually add a user to the accesses database:

Access.create(user_id: 20, workshop_id: "http-fundamentals")

Snip20140523_3

In the application the admin user will choose which workshop a user has access to, and then grant access (this will create a record containing the name of the workshop the user has access to) by clicking a button.

The point in this part of the application is that through clicking the button it will automatically add the record to the database behind the scenes. Therefore it needs to be able to grab the user_id and workshop_id from somewhere so that it happens automatically for each user, otherwise the poor admin user would have to manually enter the information into the database which would be really boring...

That information is stored within the params hash. Params hashes are used to access data sent in by the user (in this case this will mean the admin user). There are two types of parameters. The first are query string parameters. You can probably recognise these from looking at the URL that appears when you search for something in a search engine. Everything that comes after the ? Is the query string and will be stored in the params hash. Query string parameters for getting information for which a user needs to be logged in to an application are not considered a very secure option. This is because they are vulnerable to CSRF attacks. This is where an authenticated user is tricked by an attacker into visiting a modified query string that causes them to perform an action that they did not want to perform.

So for the URL http://www.example.com/?foo=2&bar=hat

params[:foo] would contain 2 and params[:bar] would contain hat.

The other type of parameter is referred to as POST data and usually comes from a form submission. The information entered or selected in the form will be stored inside a params hash once submitted meaning that you will be able to grab data from there to process in the part of the application that the form is routed to.

So in this application I used a protected method to index and encapsulate the parameters. The :workshop_id is the key to the params hash, therefore its value will be the workshop_id (which was selected and put in there thanks to the submission of a form). Same with the user_id.

Snip20140523_4

It is more common to see a params hash indexed using (params[:user_id])

An example of which is shown below:

Snip20140526_6

Params hashes can also contain routing parameters.

A routing parameter will contain the relevant :id. So if I had added another hidden field into the form and passed in :id, it would have put the access id for that user into the params hash. So for the user shown below the value of that :id would be 73. If you create a database it will automatically have an id column. This is useful to keep in mind for routes that require you to pass in an id.

Snip20140526_7

=>#<Access id: 73, user_id: 20, workshop_id: "http-fundamentals",
created_at: "2014-05-23 15:41:15">

To index params in conjunction with a database you will need to use active record queries.

http://guides.rubyonrails.org/active_record_querying.html

So in the rails console I can run Access.find_by_user_id_and_workshop_id(5, “http-fundamentals”) then it will return the first record in the database that fits that criteria.

Snip20140526_8

So I could use this in the application by indexing params hashes in the argument to the active record query.

Snip20140526_10

There are other very useful forms of hashes in Rails (well key-value pairs which are not technically hashes but behave exactly like them...) which include cookies, flashes and session hashes. I will save talking about these for a future blog post but for now it is at least useful to understand how having a secure knowledge of how Ruby hashes work is important, as this knowledge will benefit you when you come to making use of these important Rails features.