Searching across tables with Wice Grid in Rails

Say that in your Rails app’s admin interface you have a table of orders, each of which is associated with a customer. You need to find orders belonging to a particular customer, by e-mail address. This is a search across two tables, orders and customers.

Wice Grid, a fantastic data grid for Rails, makes this search easy. Check out our intro to Wice Grid if you haven’t already, then come back here for this trick.

In your controller, when you declare your grid, include the other table that you’re searching.

Now, in your view, when you define the column that contains the customer’s e-mail address, reference the model (Customer) and the field within that model (email).

Wice generates a search box above the customer e-mail column. Enter an e-mail address to find orders a associated with that customer.

Try out Wice Grid in your Rails app! It makes admin interfaces much easier to build.

For more background, check out our intro to Wice Grid.

If you’re building a broader search feature for your app’s users, check out our intro to full-text search in Rails.

Creating a Ruby gem for one-time announcements, part 3 – targeting messages to users

This is part 3 of building a gem for targeted, one-time announcements to users in Rails. See part 2 and part 1.

We’ll focus on targeting announcements to certain types of users. For instance, the admin may want to deliver an announcement only to users who have subscriptions.

A field in the Announcements table called limit_to_users will specify which types of users should receive the announcement.

limit_to_users can contain multiple conditions, so we’ll make it an array of hashes. ActiveRecord allows objects like these to be stored in text fields in the database, using the serialize method in a model.

This test validates that the field works as intended, storing conditions and allowing them to be retrieved. Here, we are sharing the announcement only with users who do not have a subscription.

Querying serialized fields is tough

It’s risky to query serialized fields in a relational database. MongoDB and similar noSQL databases are tuned for fast queries of free-form information, while Postgres and its SQL siblings are not.

We need to figure out which announcement to serve to which user, even though the conditions are stored in a query-resistant serialized field.

Houston, we’ve got loops

Maybe we should grab all active announcements that the current user has not read, and cycle through them to find the latest one that is relevant to the user.

My first try at this includes two loops, one inside the other, which:

  1. Cycle through each active, unread announcement
  2. For each announcement, cycle through each condition

Loops carry potential performance issues, especially when nested. In this case, we came as far as we could with a query, and used loops for the rest.

The loops do not re-query the database, thus avoiding an n+1 query problem, so they should be pretty quick. We’ll test performance in past 4, coming soon.

Creating a Ruby gem for one-time announcements, part 2 – TDD, marking as read

In part 1, I talked about the need to announce things to users in a Rails app. The announcements should be scheduled, shown to each user only once, and targeted to particular types of users.

We’re building a Ruby gem to enable this.

Tests

I started by writing tests, describing what the one-time announcements gem should do. Test driven development (TDD) can be controversial, but I find that it helps me plan and identify issues earlier in development.

I learned how to test from Everyday Rails Testing with RSpec. The author continually updates it as new versions of Rails and RSpec are released.

The first tests confirm, at the model level, that announcements can be:

  1. Created
  2. Scheduled
  3. Marked as read

These tests pass with the current Announcement model:

Marking announcements as read

Each user should see a particular announcement only once, so I needed a way to mark announcements as read.

The unread_by scope above shows only those announcements which the user has not read. It uses the AnnouncementView model to see who has read which announcements:

The current method chains the ready_for_delivery, unread_by, and in_delivery_order scopes to determine which announcement to deliver.

This StackExchange thread helped, and I took inspiration from a gem specifically for marking messages as read.

What’s next

In part 3, we’ll look at how to target announcements to particular types of users. For instance, what if you have an announcement just for users on a particular subscription plan?

Creating a Ruby gem for one-time announcements – part 1

At Cook Smarts we need a way to provide one-time announcements to customers, right inside our Rails app.

For instance, we may want to notify our paying users of a new feature when they log in.

Once the customer reads the announcement, he or she can close it and will never see it again.

The closest Ruby gem I could find is thoughtbot’s paul_revere. It’s elegant and simple, providing one-off announcements to an app.

It does not, however, support:

  • Start and end dates for an announcement What if an announcement is relevant only for a period of time?
  • Announcements to a subset of users What if an announcement is relevant only to some users?
  • Remembering across devices that a user closed a message If the user already read a message on desktop, why should they see it again on mobile?

What about keeping it simple?

One-off announcements may seem simple at first, but in practice, they benefit from more granularity.

Showing people only the announcements they need, at the right time, and only once, increases the messages’ potency.

Filtering announcements by user characteristics

Each announcement will be filtered based on conditions about the current user. For instance, is the user on a free trial or paid plan? When they did they sign up?

Perhaps we need to grab all announcements the user has not read with a simple database query, and then use some logic to see which of those is relevant to the user.

In any case, I’m looking for a safe, customizable way to target one-time messages.

What’s next

Next, I’ll take you through the process of creating a Ruby gem for one-time announcements. Stay tuned for part 2…

Supporting guest users in a Rails app

Many apps place content behind an account wall. Bringing that wall down and allowing guest users can make content more discoverable and open it up to search engines.

You might often reference the logged in user, to get their first name, for instance. Most authentication gems, like Devise, provide a current_user helper that contains whoever is logged in.

If no one is logged in, however, current_user will trigger an error if you try to a call a method on it. For instance, current_user.first_name would result in an error if no one is logged in.

To get around this, create a guest user class called GuestUser, and give it properties that a real user would have.

Add any other properties that you use with current_user.

Finally, adjust the current_user method to use GuestUser:

If you are using Devise, use this code instead of the previous block to avoid a potential conflict:

Now, you never have to check current_user for nil because it will always equal an actual user or the guest user.

Explore this concept:

Use ActiveRecord scopes, not class methods, in Rails to avoid errors

In Rails, scopes provide a shortcut your models’ most frequently used queries.

For instance, on a Widgets model, you might have a scope called available, which runs Widgets.where(“quantity_in_stock > 0”).

You can achieve the same effect with a class method on the Widgets model.

In either case,  Widget.available returns an ActiveRecord relation with the matching records, just as if you had called the where method directly.

If class methods and scopes do the same thing, why would you use one over the other?

Scopes, it turns out, are less error-prone.

To find out why, we need to examine a more complex query.

Say that widgets have a discontinuation_date. Once a widget hits that date, it is no longer available.

We’ll expand our available scope/method to take the discontinuation_date into account.

Here, we show widgets that are currently available and haven’t hit their discontinuation date.

Now, say you called Widget.available(nil).order(“title”).

The class method returns a nil object, and you receive an error stating that there is no method order on a nil object. Not good!

The scope, on the other hand, returns a blank ActiveRecord relation. Running order on a blank ActiveRecord relation returns that same relation. No error. Good!

Choose scopes over class methods in your models.


Scopes avoid the problem of nil objects, which make code messy and error-prone.

Scopes don’t return the dreaded nil objects, instead returning a blank relation on which you can run any ActiveRecord method. You could say they implement the null object pattern.

The most direct and bullet-proof way to avoid nil object errors is to avoid nil objects
If You Gaze Into Nil, Nil Gazes Also Into You by thoughtbot

For more details on the differences between class methods and scopes, check out Active Record Scopes vs. Class Methods on Plataformatic’s blog.

Easy data grids for your Rails app, with Wice Grid

Sometimes we need to show tables of data in a Rails app, sort of like souped-up spreadsheets. The tables, or grids, should handle tons of records, support searching and filtering, and allow for customization.

Ever try coding a data grid yourself? It’s hard. You need to implement pagination, filtering, searching, ordering, etc., every time. Why not use a pre-built solution and built off of it instead?

Wice Grid is the quickest grid solution out there for Rails. It takes care of both the client and server. It’s not AJAX-y and gorgeous, but it’s functional and reliable.

At Cook Smarts, we used Wice Grid to improve the admin interface without leaping to a full-scale solution like Rails Admin.

For instance, Cook Smarts’ customers can purchase gift certificates for their friends. Site admins need to see all gift certificates and search for particular ones. The easiest way for them to do this is through a data grid.

To get started, check out the Wice Grid page on GitHub.

Getting up and running is easy:

Follow the installation instructions on the Wice GitHub page

Add the grid code to a controller method, with the model whose data should appear in the grid.

Then, add the grid code to a view, referencing the grid you specified in the controller. Add columns, specifying the attribute as the field name in the database and the name as the text to appear in the header of the grid.

Customizing the order, filtering, search, and pagination is easy. Check out the Wice Grid GitHub page for instructions.

Wice Grid would be even better if it incorporated AJAX, to avoid page reloads when searching, for instance. However, that is the trade-off for its extremely quick setup.

Rails Admin, a quick admin interface for your Rails app

Most apps have an admin interface, a place where the developers and special users can make changes to the database.

Creating your own admin interface is time-consuming, and can take the focus away from developing user-facing features. Figuring that admin interfaces have similar needs, frameworks have emerged that help get your started.

With Rails Admin, you can edit your database on dev and production, in a user-friendly way, without coding your own admin interface.

Its closest competition is Active Admin, which I see as too complex for a convenience tool.

Quick start

Add this to your Gemfile:

In a terminal window, while inside the path of your app, run

You now have an admin panel, located at http://yourapp.com/admin

Two essential steps remain.

One, make sure your models are defined correctly. Have you defined associations, like belongs_to, has_one, and has_many, as needed?

Two, restrict access to your admin interface. tell Rails Admin who should be allowed access.

How it looks

My app will deliver online courses. So far, it contains two tables:

  • Lessons
  • Components

Each component falls under a lesson. In Rails-speak, a component :has_one lesson, and one lesson :has_many components.

Rails Admin looks at my models and shows them in its left navigation. I never had to separately tell Rails Admin the structure of my database.

Rails Admin - left navigation

When I click on a table, I see its records.

Rails Admin - record editor

I can edit records. Since components are related to lessons, I can add components to lessons and associate each component to a lesson, all within Rails Admin.

Enjoy!

Rails Admin can help you launch faster by removing the need to develop your own custom admin interface.

At the start, either use a quick solution like Rails Admin or create your own custom admin interface. You can always move from Rails Admin to a custom interface later.

For more information about why you’d use Rails Admin, check out this presentation. Jump into the details by visiting the Rails Admin wiki.

Editor’s note

This is the beginning of a new series, Up and Running. We’ll tell you how to get up and running with several developer tools, quickly and easily. Get updates about what we cover next.

Markdown in Rails with Redcarpet

Why it’s awesome

Redcarpet is an extremely quick way to show Markdown as formatted HTML in your Ruby / Rails app.

Markdown is a simple way to format text. Think of it as an easier version of HTML.

In Markdown, this:

Becomes this:

Hello, this is bold and this is italic.

Users can enter Markdown into regular text fields, and you can store it as text in your database. Then, with Redcarpet, you can render the Markdown as HTML.

You might allow users to comment within your app using regular text or Markdown, and then show those comments with formatting.

Quick start

Add this to your Gemfile:

Store Markdown in a regular text field within your database. To the user, you can present a plain text field and link to a Markdown quick reference.

Once some Markdown is in your database, you can convert it to HTML in your controller…

… then show the resulting HTML in a view:

In the example above, we used the body of a comment as an example.

Check out the documentation and this video overview.

In closing

I love Markdown, and will use this tool whenever I need to maintain static, formatted content in my app.

Rolling out Markdown editing to end users is trickier, since many may not be familiar with it. However, allowing people to use Markdown is different from requiring it. If you allow Markdown in comments, for instance, place a note under your new comment field stating that Markdown is an option, and link to a quick reference.

The Up and Running series

This is part of the Up and Running series, showing you how to jump onboard to useful developer tools. Hear about what’s coming next by joining our e-mail list.

Creating and selling a course online – the tools

When I first took an course on edX, I was struck by the power of online education. There I was, learning Ruby on Rails for free, taking the same curriculum from the same professors as a group of students at Berkeley. I watched videos from the instructors, took quizzes, completed assignments, and tracked my progress along the way.

The next wave of online education, I believe, will come from individual experts marketing online courses. Sean McCabe is a prime example. He holds a unique skill, hand lettering, and successfully marketed a course teaching others how to master the skill and build a business from it.

The first challenge to teaching online is, of course, developing content. Another is finding a place to host and sell that content.

This guide highlights tools available for hosting and selling online courses, aiming to at least cover the different categories available to course creators. The guide is aimed toward robust online courses that may include video, written material, quizzes, and discussion. (Simpler courses – containing eBooks and other static, downloadable content – could be sold through services like Gumroad, with no need for robust courseware.)

Core features

First, it’s important to highlight how tools differ.

Branding independence (B)
Does the author retain control of the his or her brand within the course? This is particularly important to those who use their courses to sell other products, like consulting, or who plan to create a related suite of courses.

Content ownership (C)
Does the course author maintain full ownership over content, including the ability to pull it from the tool and/or publish it elsewhere?

Course design (D)
Can the author easily design a robust course, without custom code or advanced customization? This allows independent authors to focus on content, not technology.

Infrastructure control (I)
Does the author retain control of content and users regardless of the uptime of external service providers? Does the course continue to exist if a service provider goes out of business?

Price control (P)
Can the author set and control the price of the course? Can others discount the price without asking the author?

User control (U)
Can the author reach out directly to course participants, on his or her own terms (assuming the course participants have agreed to such outreach)?

Now, for the tools…

Marketplaces

Core features: C-, D, P-, U-

Udemy and Skillshare are two examples of marketplaces. They allow anyone to set up and sell a course. They ask for no upfront fees from authors, host all course materials, and promote courses to a wide community of users. In exchange for these services, they take a cut of course revenue.

Marketplaces provide limited content ownership, price control, and user control. To find economy of scale, the services need to take something away from each of those elements. They’re centrally hosted and thus provide no infrastructure control. They take on the brand of the marketplace, so offer you no branding independence.

Authors maintain control over course content and retain ownership, but give up control over pricing. Both services apply their own discounts to courses (though may provide a way for authors to opt out), impacting revenue.

Sean McCabe shared his experiences with one such provider, in this podcast worth listening to if you are comparing your options. In short, he lost control over his content and pricing.

Subscription communities

Core features: D

Subscription communities like Lynda, Treehouse, and Learnable bundle courses into subscriptions. They provide the course author with no content, price, user, infrastructure, or branding control, but do provide rich course design tools. In exchange, they provide guaranteed payment to course authors.

The author receives an upfront payment and commissions based on the number of people who take the course (and often other factors).

Hosted tools

Core features: C, P, U, B-, D

Thinkific and similar tools provide full content, price, user control, and course design tools, but no infrastructure control. They generally charge monthly and transaction fees to course authors, their only revenue source.

They provide limited branding control, allowing you to place your own logo and styles on your course. Generally, though, it is somewhat clear that the course is hosted on their platform.

Self-hosted WordPress plugins

Core features: B, C, P, I-, U

WordPress has a number of plugins that allow people to sell content online. MemberMouse and Wishlist Member are two examples. These tools live on your own WordPress site, not on the service provider’s platform.

They provide full content, price, and user control. They provide full branding control, as you can customize your WordPress site to your heart’s content.

They do not provide complete infrastructure control. MemberMouse charges course authors a monthly fee, and phones home to ensure it’s collected. It’s not entirely clear what happens if that home goes away (i.e. MemberMouse goes out of business). MemberMouse also handles a few things on its own servers, like recurring billing.

Importantly, such tools are not courseware, per se. They take care of the business side of running an online course – that is, allowing people to purchase courses on a subscription or one-time basis – but do not provide the user interface for the course itself. It is up to the author to create the course within WordPress.

Custom development

Core features: C, P, U, I, B, D

There’s no beating the control you get with custom development, but it’s expensive. It’s worth listening to Sean McCabe’s take on what he went through to build his own platform, and the rewards he gained.

Open-source tools

Solid open-source tools for selling online courseware don’t really exist, from what I’ve seen.

In conclusion

There is a gap in the market for solid, affordable self-hosted solutions that would deliver all of the elements first identified in this article. In the mean time, authors are left to choose custom development or consider tools like those listed above.