jollopre / activerecord_workshop

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Active Record - Object Relational Mapping for Ruby

ActiveRecord is an Object Relational Mapper (ORM). It can represent business data and logic, however we are going to focus only in its ability to facilitate the creation and use of ruby objects that map business data that is persisted into a relational database.

Throughout this workshop, we are going to tackle 3 topics:

  • Performing database operations in a object-oriented fashion
  • Representing data models and their associations
  • Explaining how to evolve a database schema over time using migrations

Database operations - Query Methods

ActiveRecord offers a rich interface that permits chaining methods in order to build from simple to complex queries. For instance, methods such as select, from, joins, where always return ActiveRecord::Relation objects. These objects are only lazy evaluated when you try to access to one of the records returned by the SQL generated.

This library also has some query methods that are not chainable, i.e. they are evaluated immediately and return single values (e.g. an instance of a model, an Integer, an Array of values, etc). The most commond used methods are find, find_by, pluck, as well as aggregated methods such as avg, count, min, max, etc.

  • where: permits building the WHERE clause according to the arguments passed. When multiple chained where are used these are concatenated using sql AND.
  • and, or, not: permits adding logical operands to the where clause.
  • group: performs sql GROUP BY on args. More info, visit.
  • having: performs sql HAVING on args. This method is used to perform conditions like sql WHERE but permits adding aggregate functions. Remember, this method requires your query to include group. More info, visit.
  • distinct: removes duplicated records according to the args passed. More info, visit.

Select fields

These methods when used, modify the select statement of a query from SELECT * ... to the arguments passed. There are currently 3 different ways:

  • select: It returns ActiveRecord::Relation therefore it can be chained with other query methods.
  • pluck: Returns an Array of the attribute values. If the resulting query returns more than one record from the db, it would be an Array of Arrays.
  • pick: It behaves like pluck but returns only one record using sql LIMIT 1 underneath.

It is important to understand that neither pluck nor pick are chainable.

Eager loading

  • preload: loads into memory the relation tables into separate queries. More info, visit.
  • eager_load: loads into memory the relation tables using a single SQL query. More info, visit.
  • includes: loads into memory the relation tables but it is smarter than preload when conditions on related tables are passed. More info, visit.

Joining tables

  • joins: performs sql INNER JOIN on args. More info, visit.
  • left_outer_joins: performs sql LEFT OUTER JOIN on args. It is behaviour used for eager loading methods such as eager_load and includes.

Agregates

There are several methods used for mapping into SQL aggregates.

Subqueries

A subquery is a query within a query. It permits increasing the expressive power of SQL. Subqueries can be used in different places inside of statements such as SELECT, WHERE, HAVING or EVEN. Also in UPDATE or DELETE.

There are two types of subqueries:

  • simple: where the inner query does not reference columns from the outer query and
  • correlated: where the inner query references columns from the outer query. These type of queries tend to be slow since they imply many executions

We can benefit of subqueries through ActiveRecord using from. More info, please visit.

Data Models and associations

TBD

Custom Attributes

ActiveRecord brings the possibility to override the type of an existing attribute defined in a model. For instance the experiment binary_uuid is overriding the binary field id with the type ORM::UuidType. This type dedicated for uuid defines how the values are converted to and from SQL when assigned to the model. Please, refer to the documentation for more details.

Migrations

TBD

Advanced

Following topics are to be explored:

  • Use explain and to_sql to get a sense of the plan executed and the SQL query generated respectively.
  • Combine several SQL statements as one atomic action using Transaction.
  • Optimistic/Pesimistic locking through ActiveRecord.
  • Combine ActiveRecord::Relation using merge.
  • Advanced ActiveRecord queries using private API Arel.

Exercises

  1. Prepare the environment for test: make test.

  2. Retrieve pricing_settings for domestic, i.e. whose currency is similar to the currency for a company, in a country given. Implementation and Test. Hint: where and joins can be used.

  3. Retrieve pricing_settings for exchange, i.e. whose currency differs from the currency for a company, in a country given. Implementation and Test. Hint: where and joins can be used.

  4. Retrieve companies having pricing_settings whose payment_method behind is from credit_card type. Implementation and Test. Hint: where, joins and distinct.

  5. Retrieve companies having pricing_settings whose payment_method behind is from credit_card type grouped by sector with totals. Implementation and Test. Hint: select, where, joins, distinct, group, count.

  6. Retrieve companies offering many pricing_settings grouped by company and country code. When a company has more than one pricing_setting offered, it is considered many. Implementation and Test. Hint: group, having, pluck.

  7. There is an query implementation together with test that retrieves a list of pricing offers for a given company and country code given. Run the following commands:

    • $ make shell
    • $ bin/console
    • $ Queries::CompanyOffersForCountry.call

    do you find anything suspicious in terms of queries executed? Could it be improved? Hint: preload, includes or eager_load.

  8. Retrieve companies offering payment_methods above average spread of pricing_settings. Implementation and Test. Hint: select, joins, where, from and distinct.

  9. There is a need to re-compute pricing_settings_count for each and every company. Implementation and Test. Hint: .find_in_batches and #update_column or correlated subquery and .update_all.

References

About


Languages

Language:Ruby 97.5%Language:Makefile 1.1%Language:Shell 0.7%Language:Dockerfile 0.6%