Skip to content

Commit 20d7732

Browse files
committed
Add support for modelling associations
1 parent 3e8bba6 commit 20d7732

27 files changed

+306
-73
lines changed

CHANGELOG.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
# Changelog
22

3+
## 0.4.0 on 2018-01-15
4+
5+
### Features
6+
- Support for has_many/belongs_to associations
7+
- Create a project README
8+
- New CHANGELOG
9+
10+
### Fixes
11+
- Models now inherit from `ApplicationRecord`
12+
13+
314
## 0.3.0 on 2018-01-11
415

516
### Features
617
- Generating a Rails 5.1.4 app on Ruby 2.5.0
718
- Dropped asset pipeline in favor of Webpacker
819
- The generated application now has a sleek, simple design based on Bootstrap
920
- Employing [Unpoly](https://unpoly.com)
10-
- New application model DSL shortcut `crud` for creating Model plus WebUI
21+
- New DSL command `crud` for creating Model plus WebUI
1122
- The generated application model is now a transformable example of katapult's features
1223

1324
### Development improvements

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ Defined on Model. Takes a name and options:
136136
model.attr :avoid, type: :plain_json # PostgreSQL "json"
137137

138138

139+
### Association
140+
Defined on Model; takes the name of another model just like you called it in the
141+
model. Adds a foreign key attribute to the model and `belongs_to`/`has_many`
142+
calls to the respective models.
143+
144+
model 'Customer' do |customer|
145+
customer.belongs_to 'Group'
146+
end
147+
148+
model 'Group'
149+
150+
139151
### WebUI
140152
Takes a name, options and a block:
141153

features/application_model.feature

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#@announce-output
2-
Feature: The application model prepared by Katapult
2+
Feature: The default application model prepared by Katapult
33

44
Scenario: Generating the application model template
55
Given a new Rails application with Katapult basics installed
@@ -19,6 +19,9 @@ Feature: The application model prepared by Katapult
1919
product.attr :mode, assignable_values: %w[public private]
2020
product.attr :provider, type: :url
2121
product.attr :import_data, type: :json
22+
23+
# Reference other models just like you called them
24+
product.belongs_to 'user'
2225
end
2326
2427
# Define a model

features/binary.feature

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Feature: Katapult binary `katapult`
6767
And the output should contain "Author: katapult <[email protected]>"
6868

6969

70-
Scenario: Transform the application model
70+
Scenario: Transform the default application model
7171
Given a new Rails application with Katapult basics installed
7272
And the default aruba exit timeout is 45 seconds
7373

features/model.feature

+42-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#@announce-output
2+
#@announce-stderr
23
Feature: Generate Models
34

45
Background:
@@ -13,11 +14,13 @@ Feature: Generate Models
1314
And I successfully transform the application model
1415
Then the file "app/models/car.rb" should contain exactly:
1516
"""
16-
class Car < ActiveRecord::Base
17+
class Car < ApplicationRecord
18+
1719
1820
def to_s
1921
"Car##{id}"
2022
end
23+
2124
end
2225
2326
"""
@@ -47,6 +50,10 @@ Feature: Generate Models
4750
end
4851
4952
"""
53+
And the file "spec/factories/factories.rb" should contain:
54+
"""
55+
factory :car
56+
"""
5057

5158

5259
Scenario: Generate ActiveRecord Model with attributes
@@ -72,13 +79,16 @@ Feature: Generate Models
7279
And I successfully transform the application model including migrations
7380
Then the file "app/models/person.rb" should contain exactly:
7481
"""
75-
class Person < ActiveRecord::Base
82+
class Person < ApplicationRecord
83+
7684
include DoesFlag[:locked, default: false]
85+
7786
has_defaults({:homepage=>"http://www.makandra.de"})
7887
7988
def to_s
8089
age.to_s
8190
end
91+
8292
end
8393
8494
"""
@@ -148,6 +158,31 @@ Feature: Generate Models
148158
Then the output should contain "Katapult::Attribute does not support option :invalid_option. (Katapult::Element::UnknownOptionError)"
149159

150160

161+
Scenario: Specify model associations
162+
When I write to "lib/katapult/application_model.rb" with:
163+
"""
164+
model('Company') { |c| c.attr :name }
165+
model 'User' do |user|
166+
user.belongs_to 'Company'
167+
end
168+
"""
169+
And I successfully transform the application model including migrations
170+
Then the file "app/models/company.rb" should contain "has_many :users"
171+
And the file "app/models/user.rb" should contain "belongs_to :company"
172+
And the file "app/models/user.rb" should contain:
173+
"""
174+
assignable_values_for :company, {:allow_blank=>true} do
175+
Company.all.to_a
176+
end
177+
"""
178+
179+
And there should be a migration with:
180+
"""
181+
create_table :users do |t|
182+
t.integer :company_id
183+
"""
184+
185+
151186
Scenario: Specify assignable values
152187
When I write to "lib/katapult/application_model.rb" with:
153188
"""
@@ -159,17 +194,21 @@ Feature: Generate Models
159194
And I successfully transform the application model including migrations
160195
Then the file "app/models/person.rb" should contain exactly:
161196
"""
162-
class Person < ActiveRecord::Base
197+
class Person < ApplicationRecord
198+
199+
163200
assignable_values_for :age, {} do
164201
9..99
165202
end
203+
166204
assignable_values_for :hobby, {:allow_blank=>true, :default=>"soccer"} do
167205
["soccer", "baseball"]
168206
end
169207
170208
def to_s
171209
age.to_s
172210
end
211+
173212
end
174213
175214
"""

features/web_ui.feature

+17-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Feature: Web User Interface
99
Scenario: Generate a Web User Interface
1010
When I write to "lib/katapult/application_model.rb" with:
1111
"""
12-
model 'customer' do |customer|
12+
crud 'customer' do |customer|
1313
customer.attr :name
1414
customer.attr :age, type: :integer
1515
@@ -22,11 +22,11 @@ Feature: Web User Interface
2222
customer.attr :first_visit, type: :datetime
2323
customer.attr :indexable_data, type: :json
2424
customer.attr :plain_data, type: :plain_json
25-
end
2625
27-
web_ui 'customer', model: 'customer' do |web_ui|
28-
web_ui.crud
26+
customer.belongs_to 'project'
2927
end
28+
29+
model('project') { |p| p.attr :title }
3030
"""
3131
And I successfully transform the application model including migrations
3232
Then the file "app/controllers/customers_controller.rb" should contain exactly:
@@ -107,6 +107,7 @@ Feature: Web User Interface
107107
:first_visit,
108108
:indexable_data,
109109
:plain_data,
110+
:project_id,
110111
)
111112
end
112113
@@ -195,6 +196,10 @@ Feature: Web User Interface
195196
= Customer.human_attribute_name(:first_visit)
196197
%dd
197198
= l(@customer.first_visit.to_date) if @customer.first_visit
199+
%dt
200+
= Customer.human_attribute_name(:project_id)
201+
%dd
202+
= @customer.project
198203
199204
"""
200205
And the file "app/views/customers/new.html.haml" should contain exactly:
@@ -250,6 +255,10 @@ Feature: Web User Interface
250255
.form-group
251256
= form.label :first_visit
252257
= form.date_field :first_visit, class: 'form-control'
258+
.form-group
259+
= form.label :project_id
260+
= form.collection_select :project_id, form.object.assignable_projects,
261+
:id, :title, { include_blank: true }, class: 'form-control'
253262
254263
.action-bar
255264
- cancel_path = @customer.new_record? ? customers_path : customer_path(@customer)
@@ -272,6 +281,7 @@ Feature: Web User Interface
272281
273282
Scenario: CRUD customers
274283
Given I am on the list of customers
284+
And there is a project with the title "title-string"
275285
276286
# create
277287
When I follow "Add customer"
@@ -284,6 +294,7 @@ Feature: Web User Interface
284294
And I check "Locked"
285295
And I fill in "Notes" with "notes-text"
286296
And I fill in "First visit" with "2022-03-25"
297+
And I select "title-string" from "Project"
287298
And I press "Save"
288299
289300
# read
@@ -296,6 +307,7 @@ Feature: Web User Interface
296307
And I should see "Locked Yes"
297308
And I should see "notes-text"
298309
And I should see "2022-03-25"
310+
And I should see "title-string"
299311
300312
# update
301313
When I follow "Edit"
@@ -308,6 +320,7 @@ Feature: Web User Interface
308320
And the "Locked" checkbox should be checked
309321
And the "Notes" field should contain "notes-text"
310322
And the "First visit" field should contain "2022-03-25"
323+
And "title-string" should be selected for "Project"
311324
312325
# destroy
313326
When I go to the list of customers
@@ -318,7 +331,6 @@ Feature: Web User Interface
318331
But I should not see "name-string"
319332
320333
"""
321-
322334
When I run cucumber
323335
Then the features should pass
324336

lib/generators/katapult/app_model/templates/lib/katapult/application_model.rb

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
product.attr :mode, assignable_values: %w[public private]
1414
product.attr :provider, type: :url
1515
product.attr :import_data, type: :json
16+
17+
# Reference other models just like you called them
18+
product.belongs_to 'user'
1619
end
1720

1821
# Define a model

lib/generators/katapult/clearance/clearance_generator.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,12 @@ def add_authentication_paths
122122
end
123123

124124
def add_user_factory
125-
inject_into_file 'spec/factories/factories.rb', <<-'CONTENT', after: 'FactoryBot.define do'
125+
factories_file = 'spec/factories/factories.rb'
126126

127+
# Remove empty factory, if it exists
128+
gsub_file factories_file, " factory :user\n\n", ''
129+
130+
inject_into_file factories_file, <<-'CONTENT', before: /end\n\z/
127131
factory :user do
128132
sequence(:email) { |i| "user-#{ i }@example.com" }
129133
password 'password'

lib/generators/katapult/cucumber_features/cucumber_features_generator.rb

+10
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,22 @@ def create_crud_feature
1212
template 'feature.feature', "features/#{model.name(:variables)}.feature"
1313
end
1414

15+
no_tasks do
16+
def belongs_tos
17+
app_model.get_belongs_tos_for model.name
18+
end
19+
end
20+
1521
private
1622

1723
def model
1824
@element
1925
end
2026

27+
def app_model
28+
model.application_model
29+
end
30+
2131
end
2232
end
2333
end

lib/generators/katapult/cucumber_features/templates/feature.feature

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ Feature: <%= model.name(:humans).titleize %>
22

33
Scenario: CRUD <%= model.name(:humans) %>
44
Given I am on the list of <%= model.name(:variables) %>
5+
<% belongs_tos.each do |model| -%>
6+
And there is a <%= model.name(:human) %> with the <%= model.label_attr.name(:human) %> "<%= model.label_attr.test_value %>"
7+
<% end -%>
58

69
# create
710
When I follow "Add <%= model.name(:human) %>"
@@ -25,7 +28,7 @@ Feature: <%= model.name(:humans).titleize %>
2528
Then I should be on the page for the <%= model.name(:variable) %> above
2629
<% model.attrs.each do |attr| -%>
2730
<%- case attr.type -%>
28-
<%- when :string, :email, :url, :integer, :money, :text -%>
31+
<%- when :string, :email, :url, :integer, :money, :text, :foreign_key -%>
2932
And I should see "<%= attr.test_value %>"
3033
<%- when :flag -%>
3134
And I should see "<%= attr.name.humanize %> Yes"
@@ -52,12 +55,10 @@ Feature: <%= model.name(:humans).titleize %>
5255
<%- end -%>
5356
<% end -%>
5457

55-
<% if model.label_attr -%>
5658
# destroy
5759
When I go to the list of <%= model.name(:variables) %>
5860
Then I should see "<%= model.label_attr.test_value %>"
5961

6062
When I follow "Destroy <%= model.label_attr.test_value %>"
6163
Then I should be on the list of <%= model.name(:variables) %>
6264
But I should not see "<%= model.label_attr.test_value %>"
63-
<% end -%>

lib/generators/katapult/model/model_generator.rb

+15
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,26 @@ def write_traits
3030
template 'app/models/shared/does_flag.rb' if flag_attrs.any?
3131
end
3232

33+
def write_factory
34+
insert_into_file 'spec/factories/factories.rb', <<-FACTORY, before: /end\n\z/
35+
factory #{ model.name(:symbol) }
36+
37+
FACTORY
38+
end
39+
3340
def generate_unit_tests
3441
Generators::ModelSpecsGenerator.new(model).invoke_all
3542
end
3643

3744
no_commands do
45+
def belongs_tos
46+
model.application_model.get_belongs_tos_for model.name
47+
end
48+
49+
def has_manys
50+
model.application_model.get_has_manys_for model.name
51+
end
52+
3853
def flag_attrs
3954
model.attrs.select(&:flag?)
4055
end

0 commit comments

Comments
 (0)