fbpx

Active Record Queries: Specifying Conditions on Associations

I ran into a ‘gotcha’ this week while setting up an active record query that already had an eager loaded association.

My goal was to only find objects that had an appointment time from the current time until the end of the day. In this case, appointments were the association and the objects were already set up to display in descending order.

Object.where(status: status)
      .includes(:appointments)
      .order('appointments.scheduled_datetime DESC')

The objects also needed to have a status of ‘scheduled’, which was already set to the variable status at the start of the controller action.

Using array conditions in my where statement, I started with the following:

Object.where(status: status)
      .includes(:appointments)
      .where('scheduled_datetime >= ? AND scheduled_datetime <= ?',             
        current_time, end_of_day)
      .order('appointments.scheduled_datetime DESC')

I had set the current_time and the end_of_day time to variables. The string making up the array condition looked good. Yet the above resulted in the following error:

PG::UndefinedTable: ERROR:  missing 
FROM-clause entry for table “appointments”

I realized that a references was needed for the conditions mentioned in the where statement. Using the example above doesn’t join the appointments table.

Object.where(status: status)
      .includes(:appointments)
      .where('scheduled_datetime >= ? AND scheduled_datetime <= ?',             
        current_time, end_of_day)
      .references(:appointments)
      .order('appointments.scheduled_datetime DESC')

Using references allows the query to know that the string in the where statement references appointments. It joins the appointments table to the query.

You may be reading this and wondering, “Couldn’t you also use joins here?”. You are right, you can use joins here, it would look something like this:

Object.where(status: status)
      .joins(:appointments)
      .where(
        'appointments.scheduled_datetime >= ? AND ' + 
          'appointments.scheduled_datetime <= ?',             
        current_time, end_of_day
       )

This looks cleaner, yet I also want to use order here. You cannot simply use order and joins when ordering on associations. You would need to use merge like this:

Object.where(status: status)
      .joins(:appointments)
      .where(
        'appointments.scheduled_datetime >= ? AND ' + 
          'appointments.scheduled_datetime <= ?',             
         current_time, end_of_day
      ).merge(Appointment.order(scheduled_datetime: :desc))

There you have it! If you are using includes in queries don’t forget the references!

Styling Select Elements with JCF

As an Apprentice Product Developer at TRIM, I’ve had the amazing opportunity of working and learning alongside an exceptional team of developers, designers, and strategists. I’m nearing the end of my apprenticeship, and wanted to share a TIL I encountered while working with Angular and TypeScript.

Having previous experience in Ruby, Rails, and JavaScript, working with Angular was different but also eye-opening. It is a lot of fun creating the functionality of a client app with components, modules, and services.

One of my biggest challenges was styling a select dropdown to match our designs. Thankfully the team ( Dom Miller!) created a JCF module that can be easily imported into an Angular project.

The JavaScript Custom Forms library (JCF) is a really great tool to customize form elements with CSS.  Once it’s imported to the project, you can place the jcf attribute in the desired element. Adding the attribute will style the element with the default jcf styles.

<select id=“dropdown-example” jcf>
    <option>Pick me</option>
    <option>No, Pick me!</option>
</select>

It is possible to include options with the jcf attribute for the select element. I’d like my dropdown to only show three options at a time. That would look something like this:

<select id=“dropdown-example”         
        jcf='{"maxVisibleItems": 3}'>
    <option>I’m option 1</option>
    <option>I’m option 2</option>
</select>

Now that the default styles and other options are set, we can add in our own styles by selecting and overriding the appropriate jcf classes. To do this, I created a file like this one within my assets folder:

project-name/src/assets/scss/base/_jcf_overrides.scss

.jcf-scrollbar-vertical {
 display: none;
}

.jcf-scrollbar-horizontal {
 display: none;
}

.jcf-list .jcf-option {
 font-size: 18px;
 font-weight: bold;
 background-color: $white;
 padding: 11px 20px;
 margin: 0px;
 text-align: left;
 border-top: 1px solid #ccc;
 cursor: pointer;
}

You can view the different jcf classes by opening your chrome dev tools on the page where the element is located, and looking near the bottom of the html. You’ll see the jcf classes created by the module.

There you have it! You now have a customized form element.