Skip to content

Commit 8552e2f

Browse files
committed
ActiveAdmin::Resource loads resources for breadcrumbs
Closes activeadmin#2266 Add `ActiveAdmin::Resource#find_resource`. This is now a centralized place to load a resource, with correct handling of primary key, decoration, etc. Then, use this new way of loading resources in the Breadcrumbs logic. This was the original impetus for for defining `ActiveAdmin::Resource#find_resource`. Previously, the `BreadcrumbsHelper` did a one-off load of the resource, which has historically been a source of bugs and/or inconsistencies. Please note that this is duplication with InheritedResources. Normally, the resource is loaded by InheritedResources, but there are situations in which ActiveAdmin needs to load resources as well (ie Breadcrumbs). It was not reasonable to use InheritedResources to load the resource (see the discussion at activeadmin#2315).
1 parent 33429ed commit 8552e2f

File tree

4 files changed

+49
-23
lines changed

4 files changed

+49
-23
lines changed

lib/active_admin/resource.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ def csv_builder
135135
@csv_builder || default_csv_builder
136136
end
137137

138+
def find_resource(id)
139+
resource = resource_class.where(resource_class.primary_key => id).first
140+
decorator_class ? decorator_class.new(resource) : resource
141+
end
142+
138143
# @deprecated
139144
def resource
140145
resource_class

lib/active_admin/view_helpers/breadcrumb_helper.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ def breadcrumb_links(path = request.path)
1313
# 3. default to calling `titlecase` on the URL fragment
1414
if part =~ /\A(\d+|[a-f0-9]{24})\z/ && parts[index-1]
1515
config = active_admin_config.belongs_to_config.try(:target) || active_admin_config
16-
obj = config.resource_class.where( config.resource_class.primary_key => part ).first
17-
name = display_name obj
16+
name = display_name config.find_resource(part)
1817
end
1918
name ||= I18n.t "activerecord.models.#{part.singularize}", :count => 1.1, :default => part.titlecase
2019

spec/unit/resource_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,5 +208,36 @@ def config(options = {})
208208
end
209209
end
210210
end
211+
212+
describe '#find_resource' do
213+
let(:resource) { namespace.register(Post) }
214+
let(:post) { stub }
215+
before do
216+
Post.stub(:where).with('id' => '12345').and_return { [post] }
217+
end
218+
219+
it 'can find the resource' do
220+
resource.find_resource('12345').should == post
221+
end
222+
223+
context 'with a decorator' do
224+
let(:resource) { namespace.register(Post) { decorate_with PostDecorator } }
225+
it 'decorates the resource' do
226+
resource.find_resource('12345').should == PostDecorator.new(post)
227+
end
228+
end
229+
230+
context 'when using a nonstandard primary key' do
231+
let(:different_post) { stub }
232+
before do
233+
Post.stub(:primary_key).and_return 'something_else'
234+
Post.stub(:where).with('something_else' => '55555').and_return { [different_post] }
235+
end
236+
237+
it 'can find the post by the custom primary key' do
238+
resource.find_resource('55555').should == different_post
239+
end
240+
end
241+
end
211242
end
212243
end

spec/unit/view_helpers/breadcrumbs_spec.rb

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,20 @@ def params; {}; end
1111
# Mock link to and return a hash
1212
def link_to(name, url); {:name => name, :path => url}; end
1313

14+
let(:post) { mock(:display_name => 'Hello World') }
15+
16+
let(:post_config) { stub(find_resource: post) }
17+
1418
let :active_admin_config do
15-
m = mock
16-
m.stub_chain(:belongs_to_config, :target, :resource_class).and_return Post
17-
m
19+
active_admin_config = stub
20+
active_admin_config.stub_chain(:belongs_to_config, :target).and_return post_config
21+
active_admin_config
1822
end
1923

2024
let(:trail) { breadcrumb_links(path) }
2125

2226
context "when request '/admin'" do
23-
let(:path){ "/admin" }
27+
let(:path) { "/admin" }
2428

2529
it "should not have any items" do
2630
trail.size.should == 0
@@ -71,16 +75,14 @@ def link_to(name, url); {:name => name, :path => url}; end
7175
end
7276

7377
context "when Post.find(1) doesn't exist" do
78+
before { post_config.stub(find_resource: nil) }
7479
it "should have a link to /admin/posts/1" do
7580
trail[2][:name].should == "1"
7681
trail[2][:path].should == "/admin/posts/1"
7782
end
7883
end
7984

8085
context "when Post.find(1) does exist" do
81-
before do
82-
Post.stub(:where).with('id' => '1').and_return{ [ mock(:display_name => 'Hello World') ] }
83-
end
8486
it "should have a link to /admin/posts/1 using display name" do
8587
trail[2][:name].should == "Hello World"
8688
trail[2][:path].should == "/admin/posts/1"
@@ -104,6 +106,7 @@ def link_to(name, url); {:name => name, :path => url}; end
104106
end
105107

106108
context "when Post.find(4e24d6249ccf967313000000) doesn't exist" do
109+
before { post_config.stub(find_resource: nil) }
107110
it "should have a link to /admin/posts/4e24d6249ccf967313000000" do
108111
trail[2][:name].should == "4e24d6249ccf967313000000"
109112
trail[2][:path].should == "/admin/posts/4e24d6249ccf967313000000"
@@ -112,7 +115,7 @@ def link_to(name, url); {:name => name, :path => url}; end
112115

113116
context "when Post.find(4e24d6249ccf967313000000) does exist" do
114117
before do
115-
Post.stub(:where).with('id' => '4e24d6249ccf967313000000').and_return{ [ mock(:display_name => 'Hello :)') ] }
118+
post_config.stub(:find_resource => mock(:display_name => 'Hello :)'))
116119
end
117120
it "should have a link to /admin/posts/4e24d6249ccf967313000000 using display name" do
118121
trail[2][:name].should == "Hello :)"
@@ -136,7 +139,7 @@ def link_to(name, url); {:name => name, :path => url}; end
136139
trail[1][:path].should == "/admin/posts"
137140
end
138141
it "should have a link to /admin/posts/1" do
139-
trail[2][:name].should == "1"
142+
trail[2][:name].should == "Hello World"
140143
trail[2][:path].should == "/admin/posts/1"
141144
end
142145
it "should have a link to /admin/posts/1/comments" do
@@ -145,17 +148,5 @@ def link_to(name, url); {:name => name, :path => url}; end
145148
end
146149
end
147150

148-
context 'when using a nonstandard primary key' do
149-
let(:path) { '/admin/posts/55555/comments' }
150-
before do
151-
Post.stub(:primary_key).and_return 'something_else'
152-
Post.stub(:where).with('something_else' => '55555').and_return{ [ mock(:display_name => 'Hello Hello!') ] }
153-
end
154-
it 'should link to /admin/posts/55555 using display name' do
155-
trail[2][:name].should == 'Hello Hello!'
156-
trail[2][:path].should == '/admin/posts/55555'
157-
end
158-
end
159-
160151
end
161152
end

0 commit comments

Comments
 (0)