Skip to content

Commit

Permalink
Implement Field::HasMany with a table on show page
Browse files Browse the repository at this point in the history
https://trello.com/c/NygJOCUM
https://trello.com/c/TERo00zt

On the `index` page, `has_many` relationships are displayed by simple
text telling how many associated objects there are.

On the `show` page, `has_many` relationships are displayed by an HTML
table, identical to the one that appears on the associated object's
`index` page.

On the `form` pages, `has_many` relationships show a message saying the
functionality is not yet implemented.

- Extracted the common table HTMl into a partial
- Extract strings to I18n
- Rename index_page_attributes -> table_attributes
- Rename `Page::Index` -> `Page::Table`
    We're now using the class to display tables both on the index page
    and on the other resource's show pages through the HasMany adapter.

Follow-up tasks:

- Implement forms for `has_many` relationships
  (needs discussion: https://trello.com/c/gjsGaU5W).
  • Loading branch information
c-lliope committed May 23, 2015
1 parent 77def55 commit aef663b
Show file tree
Hide file tree
Showing 24 changed files with 171 additions and 55 deletions.
4 changes: 2 additions & 2 deletions app/controllers/dashboard_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
require "pages/form"
require "pages/index"
require "pages/table"
require "pages/show"

class DashboardController < ApplicationController
def index
@resources = resource_class.all
@page = Page::Index.new(dashboard)
@page = Page::Table.new(dashboard)
end

def show
Expand Down
4 changes: 3 additions & 1 deletion app/dashboards/customer_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ def attribute_types
email: :email,
lifetime_value: :string,
name: :string,
orders: :has_many,
}
end

def index_page_attributes
def table_attributes
attributes
end

Expand All @@ -31,6 +32,7 @@ def attributes
:name,
:email,
:lifetime_value,
:orders,
]
end
end
2 changes: 1 addition & 1 deletion app/dashboards/line_item_dashboard.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "base_dashboard"

class LineItemDashboard < BaseDashboard
def index_page_attributes
def table_attributes
attributes + [:total_price]
end

Expand Down
8 changes: 6 additions & 2 deletions app/dashboards/order_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ def attribute_types
address_state: :string,
address_zip: :string,
customer: :belongs_to,
line_items: :has_many,
total_price: :string,
}
end

def index_page_attributes
def table_attributes
attributes
end

def form_attributes
attributes - [:id]
attributes - [:id, :total_price]
end

def show_page_attributes
Expand All @@ -36,6 +38,8 @@ def attributes
:address_state,
:address_zip,
:customer,
:line_items,
:total_price,
]
end
end
2 changes: 1 addition & 1 deletion app/dashboards/product_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def attribute_types
}
end

def index_page_attributes
def table_attributes
attributes
end

Expand Down
31 changes: 31 additions & 0 deletions app/views/dashboard/_table.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<table>
<thead>
<tr>
<th><%= table_presenter.resource_name.titleize %></th>

<% table_presenter.attribute_names.each do |attr_name| %>
<th><%= attr_name.to_s.titleize %></th>
<% end %>
<th colspan="2"></th>
</tr>
</thead>

<tbody>
<% resources.each do |resource| %>
<tr>
<td><%= link_to resource.to_s, resource %></td>

<% table_presenter.attributes_for(resource).each do |attribute| %>
<td><%= render attribute %></td>
<% end %>
<td><%= link_to t("administrate.actions.edit"), [:edit, resource] %></td>
<td><%= link_to(
t("administrate.actions.destroy"),
resource,
method: :delete,
data: { confirm: t("administrate.actions.confirm") }
) %></td>
</tr>
<% end %>
</tbody>
</table>
27 changes: 1 addition & 26 deletions app/views/dashboard/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,4 @@
<%= link_to "New #{@page.resource_name.titleize.downcase}",
[:new, @page.resource_name] %>

<table>
<thead>
<tr>
<th><%= @page.resource_name.titleize %></th>

<% @page.attribute_names.each do |attr_name| %>
<th><%= attr_name.to_s.titleize %></th>
<% end %>
<th colspan="2"></th>
</tr>
</thead>

<tbody>
<% @resources.each do |resource| %>
<tr>
<td><%= link_to resource.to_s, resource %></td>

<% @page.attributes_for(resource).each do |attribute| %>
<td><%= render attribute %></td>
<% end %>
<td><%= link_to 'Edit', [:edit, resource] %></td>
<td><%= link_to 'Destroy', resource, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<%= render "table", table_presenter: @page, resources: @resources %>
1 change: 1 addition & 0 deletions app/views/fields/form/_has_many.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sorry, nested forms for has-many relationships are not yet supported.
1 change: 1 addition & 0 deletions app/views/fields/index/_has_many.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= pluralize(has_many.data.count, has_many.attribute.to_s.humanize.downcase) %>
5 changes: 5 additions & 0 deletions app/views/fields/show/_has_many.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= render(
"table",
table_presenter: has_many.associated_table,
resources: has_many.data
) %>
4 changes: 4 additions & 0 deletions config/i18n-tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ search:
- "app/pages"
- "app/views"

data:
read:
- config/locales/administrate.%{locale}.yml

ignore_unused:
- activerecord.*
- date.*
Expand Down
6 changes: 6 additions & 0 deletions config/locales/administrate.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
en:
administrate:
actions:
edit: Edit
destroy: Destroy
confirm: Are you sure?
2 changes: 2 additions & 0 deletions lib/base_dashboard.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "fields/belongs_to"
require "fields/email"
require "fields/has_many"
require "fields/image"
require "fields/string"

Expand All @@ -20,6 +21,7 @@ def field_registry
{
belongs_to: Field::BelongsTo,
email: Field::Email,
has_many: Field::HasMany,
image: Field::Image,
string: Field::String,
}
Expand Down
20 changes: 20 additions & 0 deletions lib/fields/has_many.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require_relative "base"
require "pages/table"

module Field
class HasMany < Field::Base
def associated_table
Page::Table.new(associated_dashboard)
end

private

def associated_dashboard
Object.const_get("#{resource_class_name}Dashboard").new
end

def resource_class_name
attribute.to_s.singularize.camelcase
end
end
end
8 changes: 8 additions & 0 deletions lib/pages/base.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module Page
class Base
def initialize(dashboard)
@dashboard = dashboard
end

def resource_name
@resource_name ||=
dashboard.class.to_s.scan(/(.+)Dashboard/).first.first.underscore
Expand All @@ -14,5 +18,9 @@ def attribute_field(dashboard, resource, attribute_name, page)
field_class(attribute_name).
new(attribute_name, value, page)
end

protected

attr_reader :dashboard
end
end
2 changes: 1 addition & 1 deletion lib/pages/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Page
class Form < Page::Base
def initialize(dashboard, resource)
@dashboard = dashboard
super(dashboard)
@resource = resource
end

Expand Down
6 changes: 1 addition & 5 deletions lib/pages/show.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Page
class Show < Page::Base
def initialize(dashboard, resource)
@dashboard = dashboard
super(dashboard)
@resource = resource
end

Expand All @@ -18,9 +18,5 @@ def attributes
attribute_field(dashboard, resource, attr_name, :show)
end
end

protected

attr_reader :dashboard
end
end
14 changes: 5 additions & 9 deletions lib/pages/index.rb → lib/pages/table.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
require_relative "base"

module Page
class Index < Page::Base
def initialize(dashboard)
@dashboard = dashboard
end

class Table < Page::Base
def attribute_names
dashboard.index_page_attributes
dashboard.table_attributes
end

def attributes_for(resource)
Expand All @@ -16,8 +12,8 @@ def attributes_for(resource)
end
end

protected

attr_reader :dashboard
def to_partial_path
"/dashboard/table"
end
end
end
6 changes: 3 additions & 3 deletions spec/dashboards/customer_dashboard_spec.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
require "rails_helper"

RSpec.describe CustomerDashboard do
describe "#index_page_attributes" do
describe "#table_attributes" do
it "includes the name and email" do
dashboard = CustomerDashboard.new

expect(dashboard.index_page_attributes).to include(:name)
expect(dashboard.index_page_attributes).to include(:email)
expect(dashboard.table_attributes).to include(:name)
expect(dashboard.table_attributes).to include(:email)
end
end

Expand Down
23 changes: 23 additions & 0 deletions spec/features/orders_show_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require "rails_helper"

feature "order index page" do
scenario "displays line item information" do
line_item = create(:line_item)

visit order_path(line_item.order)

expect(page).to have_content(line_item.unit_price)
expect(page).to have_content(line_item.quantity)
expect(page).to have_content(line_item.total_price)
expect(page).to have_link(line_item.product.to_s)
end

scenario "links to line items" do
line_item = create(:line_item)

visit order_path(line_item.order)
click_on(line_item.to_s)

expect(page).to have_header(line_item.to_s)
end
end
15 changes: 15 additions & 0 deletions spec/features/show_page_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@
expect(page).to have_content(customer.email)
end

it "displays each of the customer's orders" do
customer = create(:customer)
orders = create_pair(:order, customer: customer)
orders.map.with_index(1) do |order, index|
create(:line_item, order: order, unit_price: 10, quantity: index)
end

visit customer_path(customer)

orders.each do |order|
expect(page).to have_link(order.to_s)
expect(page).to have_content(order.total_price)
end
end

it "link-ifies the email" do
customer = create(:customer)

Expand Down
27 changes: 27 additions & 0 deletions spec/lib/fields/has_many_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "spec_helper"
require "fields/has_many"

describe Field::HasMany do
describe "#to_partial_path" do
it "returns a partial based on the page being rendered" do
page = :show
items = double
field = Field::HasMany.new(:items, items, page)

path = field.to_partial_path

expect(path).to eq("/fields/#{page}/has_many")
end
end

describe "#associated_table" do
it "returns an index page for the dashboard of the associated attribute" do
orders = []
field = Field::HasMany.new(:orders, orders, :show)

page = field.associated_table

expect(page).to be_instance_of(Page::Table)
end
end
end
4 changes: 0 additions & 4 deletions spec/lib/pages/index_spec.rb

This file was deleted.

4 changes: 4 additions & 0 deletions spec/lib/pages/table_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "pages/table"

describe Page::Table do
end

0 comments on commit aef663b

Please sign in to comment.