This example demonstrates the usage of the --alt-foreign-key-lookup
flag in the settings. Using this flag, you can specify related entities to be displayed as lookups (where the user must supply an email, for example, to look up the related record) instead of drop-downs.
Let’s assume a Company has_many :company_users
and also a Company has_many :users, through: :company_users
rails generate model Company name:string
rails generate model User name:string email:string
rails generate model CompanyUser company_id:integer user_id:integer
Now modify your models like so:
app/models/company.rb
class Company < ApplicationRecord
has_many :company_users
has_many :users, through: :company_users
end
app/models/company_user.rb
class CompanyUser < ApplicationRecord
belongs_to :company
belongs_to :user
def to_label
"#{user.email} for #{company.name}"
end
end
app/models/user.rb
class User < ApplicationRecord
has_many :company_user
end
config/routes.rb
Rails.application.routes.draw do
resources :companies do
resources :company_users
end
end
Typically, you would be constructing a CompanyUsers portal on the Company page. (Showing you only CompanyUsers associated with that company.)
Let’s do that now with Hot Glue
rails generate hot_glue:scaffold Company --downnest=company_users --gd --smart-layout
rails generate hot_glue:scaffold CompanyUser --nested=company --gd --smart-layout
(This does not use the --alt-foreign-key-lookup
option. We’ll throw away this code and regenerate it later using a lookup later in this demo.)
Before we continue, let’s make 10 fake users. Drop into rails console
and type:
10.times{faker = FFaker::Name.name; User.create!(email: "#{faker.gsub(' ','_').downcase}@#{FFaker::Internet.email.split('@')[1]}", name: faker)}
You will now have 10 fake users in the database.
If you start your Rails app and navigate to /companies
, here’s what you find:
Notice that I can associate any of the 10 users in the database to this company using the drop-down list. Still, all I am doing is creating and deleting join records for CompanyUser.
You could use Hawking to limit what is shown in the drop-down (covered in Examples #3 and #4), but instead, the Alternative Lookup Mechanism allows you to give lookup access to the operator so they can look up a remote record by uniquely identifying it. For example, instead of picking from a drop-down, they must specify a the complete email address of the associated user.
What if we don’t want all users to appear here in a list? Instead, we want the user to input the unique email address which can be found on the related user record.
rails generate hot_glue:scaffold CompanyUser --alt-foreign-key-lookup=user_id{email} --nested=company --gd --smart-layout
Here, we are telling Hot Glue that for the foreign key user_id
relationship (to the User object), we want to look up a related value email on the user object instead of displaying a drop-down.
Now, we see a text input field to enter the associated email address. Under the hood, we are using a .find_by
, so if the associated thing isn’t found, we get this:
An error message tells the user it must belong to the company (it behaves just like the normal user_id
field would, but instead it looks up the specified email address of the Users table).
Here, we see that if we correctly enter the email addresses of the associated objects, we can use the lookup mechanism to create join records to those objects:
You get an error if you enter an email that isn’t found.
With Automatic Creation
Instead of failing when it doesn’t find a matching User by email, we can modify the Alt Lookup to use a .find_or_create_by(...)
instead of .find_by(...)
by adding a plus (+) to the lookup field. This will have the effect of creating new User records if they aren’t found (and also otherwise valid):
rails generate hot_glue:scaffold CompanyUser --alt-foreign-key-lookup=user_id{email+} --nested=company --gd --smart-layout
Now, with this special syntax using the plus symbol (+), the underlying code will use .find_or_create_by(email: __)
so if you enter an email that isn’t found, a new User record will be created.