nice_partials 0.1.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +213 -1
- data/Gemfile +10 -0
- data/README.md +208 -77
- data/Rakefile +2 -9
- data/lib/nice_partials/helper.rb +5 -18
- data/lib/nice_partials/monkey_patch.rb +106 -44
- data/lib/nice_partials/partial/content.rb +54 -0
- data/lib/nice_partials/partial/section.rb +48 -0
- data/lib/nice_partials/partial/stack.rb +19 -0
- data/lib/nice_partials/partial.rb +91 -19
- data/lib/nice_partials/version.rb +1 -1
- data/lib/nice_partials.rb +8 -10
- data/nice_partials.gemspec +10 -3
- metadata +22 -17
- data/.gitignore +0 -3
- data/.travis.yml +0 -18
- data/test/fixtures/_basic.html.erb +0 -2
- data/test/fixtures/_card.html.erb +0 -13
- data/test/fixtures/card_test.html.erb +0 -9
- data/test/renderer_test.rb +0 -57
- data/test/test_helper.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3b70755595cff02588aa600004e44ec9f20847a4fdd026e0326876a2cad7f52
|
4
|
+
data.tar.gz: 24e42267606eb6a56ed481d2b82d137210618dff3282f6586036aa68bfad71c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de339636e922f606a268eb0a9888686e3f0c6b3bdd0f874c8c50998a55437dfc8dff7f4a1c4293d4814277f75a49a959aa47ba9318ad9d9898d651c87d5fc6f8
|
7
|
+
data.tar.gz: ed7d3ff442df563d12aba16982a7a3ecae8a5f5b3022255e733bd2b5fd816c828064ddb659162839ef234fc26b22bd3f3a3a6be175e918a5518688a5cfe8bde2
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,221 @@
|
|
1
1
|
## CHANGELOG
|
2
2
|
|
3
|
+
* Fix rendering with special characters in a view path.
|
4
|
+
|
5
|
+
Ref: https://github.com/bullet-train-co/nice_partials/pull/70
|
6
|
+
|
7
|
+
* Seed Nice Partials content from `local_assigns`
|
8
|
+
|
9
|
+
Previously, the only way to assign content to a Nice Partial was through passing a block:
|
10
|
+
|
11
|
+
```erb
|
12
|
+
# app/views/posts/show.html.erb
|
13
|
+
<%= render "posts/post", byline: "Some guy" %>
|
14
|
+
|
15
|
+
# app/views/posts/_post.html.erb
|
16
|
+
<%= render "card" do |partial| %>
|
17
|
+
<% partial.title "Hello there" %>
|
18
|
+
<% partial.byline byline %> <%# `byline` comes from the outer `render` call above. %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
Now, Nice Partials will automatically use Rails' `local_assigns`, which contain any `locals:` passed to `render`, as the seed for content. So this works:
|
22
|
+
|
23
|
+
```erb
|
24
|
+
<%= render "card", title: "Hello there", byline: byline %>
|
25
|
+
```
|
26
|
+
|
27
|
+
And the `card` partial is now oblivious to whether its `title` or `byline` were passed as render `locals:` or through the usual assignments in a block.
|
28
|
+
|
29
|
+
```erb
|
30
|
+
# app/views/_card.html.erb
|
31
|
+
<%= partial.title %> written by <%= partial.byline %>
|
32
|
+
```
|
33
|
+
|
34
|
+
Previously to get this behavior you'd need to write:
|
35
|
+
|
36
|
+
```erb
|
37
|
+
# app/views/_card.html.erb
|
38
|
+
<%= partial.title.presence || local_assigns[:title] %> written by <%= partial.byline.presence || local_assigns[:byline] %>
|
39
|
+
```
|
40
|
+
|
41
|
+
Passing extra content via a block appends:
|
42
|
+
|
43
|
+
```erb
|
44
|
+
<%= render "card", title: "Hello there" do |partial| %>
|
45
|
+
<% partial.title ", and welcome!" %> # Calling `partial.title` outputs `"Hello there, and welcome!"`
|
46
|
+
<% end %>
|
47
|
+
```
|
48
|
+
|
49
|
+
* Add `NicePartials::Partial#slice`
|
50
|
+
|
51
|
+
Returns a Hash of the passed keys with their contents, useful for passing to other render calls:
|
52
|
+
|
53
|
+
```erb
|
54
|
+
<%= render "card", partial.slice(:title, :byline) %>
|
55
|
+
```
|
56
|
+
|
57
|
+
* Fix `partial.helpers` accidentally adding methods to `ActionView::Base`
|
58
|
+
|
59
|
+
When using `partial.helpers {}`, internally `class_eval` would be called on the Partial instance, and through `delegate_missing_to` passed on to the view context and thus we'd effectively have a global method, exactly as if we'd just used regular Rails view helpers.
|
60
|
+
|
61
|
+
* Let partials respond to named content sections
|
62
|
+
|
63
|
+
```erb
|
64
|
+
<% partial.content_for :title, "Title content" %> # Before
|
65
|
+
<% partial.title "Title content" %> # After
|
66
|
+
|
67
|
+
# Which can then be output
|
68
|
+
<% partial.title %> # => "Title content"
|
69
|
+
<% partial.title? %> # => true
|
70
|
+
```
|
71
|
+
|
72
|
+
Note, `title` responds to `present?` so rendering could also be made conditional with:
|
73
|
+
|
74
|
+
```erb
|
75
|
+
<% partial.title if partial.title? %> # Instead of this…
|
76
|
+
<% partial.title.presence %> # …you can do this
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Passing procs or components
|
80
|
+
|
81
|
+
Procs and objects that implement `render_in`, like ViewComponents, can also be appended as content:
|
82
|
+
|
83
|
+
```erb
|
84
|
+
<% partial.title { "some content" } %>
|
85
|
+
<% partial.title TitleComponent.new(Current.user) %>
|
86
|
+
```
|
87
|
+
|
88
|
+
#### Capturing `options`
|
89
|
+
|
90
|
+
Options can also be captured and output:
|
91
|
+
|
92
|
+
```erb
|
93
|
+
<% partial.title class: "text-m4" %> # partial.title.options # => { class: "text-m4" }
|
94
|
+
|
95
|
+
# When output `to_s` is called and options automatically pipe through `tag.attributes`:
|
96
|
+
<h1 <% partial.title.options %>> # => <h1 class="text-m4">
|
97
|
+
```
|
98
|
+
|
99
|
+
#### Proxying to the view context and appending content
|
100
|
+
|
101
|
+
A content section appends to its content when calling any view context method on it, e.g.:
|
102
|
+
|
103
|
+
```erb
|
104
|
+
<% partial.title.t ".title" %>
|
105
|
+
<% partial.title.link_to @document.name, @document %>
|
106
|
+
<% partial.title.render "title", user: Current.user %>
|
107
|
+
<% partial.title.render TitleComponent.new(Current.user) do |component| %>
|
108
|
+
<% … %>
|
109
|
+
<% end %>
|
110
|
+
```
|
111
|
+
|
112
|
+
#### Building elements with `tag` proxy
|
113
|
+
|
114
|
+
These `tag` calls let you generate elements based on the stored content and options:
|
115
|
+
|
116
|
+
```erb
|
117
|
+
<% partial.title "content", class: "post-title" %> # Adding some content and options…
|
118
|
+
<% partial.title.h2 %> # => <h2 class="post-title">content</h2>
|
119
|
+
<% partial.title.h2 "more" %> # => <h2 class="post-title">contentmore</h2>
|
120
|
+
```
|
121
|
+
|
122
|
+
* Add `NicePartials#t` to aid I18n.
|
123
|
+
|
124
|
+
When using NicePartials with I18n you end up with lots of calls that look like:
|
125
|
+
|
126
|
+
```erb
|
127
|
+
<% partial.title t(".title") %>
|
128
|
+
<% partial.description t(".header") %>
|
129
|
+
<% partial.byline t("custom.key") %>
|
130
|
+
```
|
131
|
+
|
132
|
+
With NicePartials' `t` method, you can write the above as:
|
133
|
+
|
134
|
+
```erb
|
135
|
+
<% partial.t :title, description: :header, byline: "custom.key" %>
|
136
|
+
```
|
137
|
+
|
138
|
+
Clarifying what keys get converted to what content sections on the partial rather than the syntax heavy `partial.… t(".…")`.
|
139
|
+
|
140
|
+
Like the Rails built-in `t` method, it's just a shorthand alias for `translate` so that's available too.
|
141
|
+
|
142
|
+
* Add `Partial#content_from`
|
143
|
+
|
144
|
+
`content_from` lets a partial extract contents from another partial.
|
145
|
+
Additionally, contents can be renamed by passing a hash:
|
146
|
+
|
147
|
+
```erb
|
148
|
+
<% partial.title "Hello there" %>
|
149
|
+
<% partial.byline "Somebody" %>
|
150
|
+
|
151
|
+
<%= render "shared/title" do |cp| %>
|
152
|
+
# Here the inner partial `cp` accesses the outer partial through `partial`
|
153
|
+
# extracting the `title` and `byline` contents.
|
154
|
+
# `byline` is renamed to `name` in `cp`.
|
155
|
+
<% cp.content_from partial, :title, byline: :name %>
|
156
|
+
<% end %>
|
157
|
+
```
|
158
|
+
|
159
|
+
### 0.1.9
|
160
|
+
|
161
|
+
* Remove need to insert `<% yield p = np %>` in partials.
|
162
|
+
|
163
|
+
Nice Partials now automatically captures blocks passed to `render`.
|
164
|
+
Instead of `p`, a `partial` method has been added to access the
|
165
|
+
current `NicePartials::Partial` object.
|
166
|
+
|
167
|
+
Here's a script to help update your view code:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
files_to_inspect = []
|
171
|
+
|
172
|
+
Dir["app/views/**/*.html.erb"].each do |path|
|
173
|
+
if contents = File.read(path).match(/(<%=? yield\(?.*? = np\)? %>\n+)/m)&.post_match
|
174
|
+
files_to_inspect << path if contents.match?(/render.*?do \|/)
|
175
|
+
|
176
|
+
contents.gsub! /\bp\.(?=yield|helpers|content_for|content_for\?)/, "partial."
|
177
|
+
File.write path, contents
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
if files_to_inspect.any?
|
182
|
+
puts "These files had render calls with a block parameter and likely require some manual edits:"
|
183
|
+
puts files_to_inspect
|
184
|
+
else
|
185
|
+
puts "No files with render calls with a block parameter found, you're likely all set"
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
189
|
+
* Support manual `yield`s in partials.
|
190
|
+
|
191
|
+
Due to the automatic yield support above, support has also been added for manual `yield some_object` calls.
|
192
|
+
|
193
|
+
Nice Partials automatically appends the `partial` to the yielded arguments, so you can
|
194
|
+
change `render … do |some_object|` to `render … do |some_object, partial|`.
|
195
|
+
|
196
|
+
* Deprecate `p` as the partial object access. Use `partial` instead.
|
197
|
+
|
198
|
+
* Expose `partial.yield` to access the captured output buffer.
|
199
|
+
|
200
|
+
Lets you access what a `<%= yield %>` call returned, like this:
|
201
|
+
|
202
|
+
```erb
|
203
|
+
<%= render "card" do %>
|
204
|
+
This is the content of the internal output buffer
|
205
|
+
<% end %>
|
206
|
+
```
|
207
|
+
|
208
|
+
```erb
|
209
|
+
# app/views/cards/_card.html.erb
|
210
|
+
# This can be replaced with `partial.yield`.
|
211
|
+
<%= yield %> # Will output "This is the content of the internal output buffer"
|
212
|
+
```
|
213
|
+
|
214
|
+
### 0.1.7
|
215
|
+
|
3
216
|
* Rely on `ActiveSupport.on_load :action_view`
|
4
217
|
* Add support for Ruby 3.0
|
5
218
|
|
6
219
|
### 0.1.0
|
7
220
|
|
8
221
|
* Initial release
|
9
|
-
|
data/Gemfile
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
2
3
|
|
3
4
|
gemspec
|
4
5
|
|
5
6
|
gem "minitest"
|
6
7
|
gem "rake"
|
7
8
|
gem "irb"
|
9
|
+
|
10
|
+
if ENV["RAILS_MAIN"]
|
11
|
+
gem "rails", github: "rails/rails", branch: "main"
|
12
|
+
else
|
13
|
+
gem "rails"
|
14
|
+
end
|
15
|
+
|
16
|
+
gem "view_component"
|
17
|
+
gem "capybara"
|
data/README.md
CHANGED
@@ -1,136 +1,254 @@
|
|
1
|
-
# nice_partials [![[version]](https://badge.fury.io/rb/nice_partials.svg)](https://badge.fury.io/rb/nice_partials)
|
1
|
+
# nice_partials [![[version]](https://badge.fury.io/rb/nice_partials.svg)](https://badge.fury.io/rb/nice_partials)
|
2
2
|
|
3
|
-
Nice Partials
|
3
|
+
Nice Partials adds ad-hoc named content areas, or sections, to Action View partials with a lot of extra power on top.
|
4
|
+
|
5
|
+
Everything happens through a new `partial` method, which at the base of it have method shorthands for partial specific `content_for` and `content_for?`s.
|
6
|
+
|
7
|
+
See, here we're outputting the `image`, `title`, and `body` sections:
|
4
8
|
|
5
9
|
`app/views/components/_card.html.erb`:
|
6
10
|
```html+erb
|
7
11
|
<div class="card">
|
8
|
-
<%=
|
12
|
+
<%= partial.image %> # Same as `partial.content_for :image`
|
9
13
|
<div class="card-body">
|
10
|
-
<h5 class="card-title"><%= title %></h5>
|
11
|
-
<% if
|
14
|
+
<h5 class="card-title"><%= partial.title %></h5>
|
15
|
+
<% if partial.body? %>
|
12
16
|
<p class="card-text">
|
13
|
-
<%=
|
17
|
+
<%= partial.body %>
|
14
18
|
</p>
|
15
19
|
<% end %>
|
16
20
|
</div>
|
17
21
|
</div>
|
18
22
|
```
|
19
23
|
|
20
|
-
|
24
|
+
Then in `render` we populate them:
|
21
25
|
|
22
26
|
```html+erb
|
23
|
-
<%= render
|
24
|
-
<%
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
ex ea commodo consequat.
|
27
|
+
<%= render "components/card", title: "Some Title" do |partial| %>
|
28
|
+
<% partial.title t(".title") %> # Same as `partial.content_for :title, t(".title")`
|
29
|
+
|
30
|
+
<% partial.body do %>
|
31
|
+
Lorem ipsum dolor sit amet, …
|
29
32
|
<% end %>
|
30
33
|
|
31
|
-
<%
|
32
|
-
<%= image_tag image_path(
|
34
|
+
<% partial.image do %>
|
35
|
+
<%= image_tag image_path("example.jpg"), alt: "An example image" %>
|
33
36
|
<% end %>
|
34
37
|
<% end %>
|
35
38
|
```
|
36
39
|
|
37
|
-
|
40
|
+
So far these uses are pretty similar to Rails' global `content_for` & `content_for?`, except these sections are local to the specific partial, so there's no clashing or leaking.
|
38
41
|
|
42
|
+
### More-in depth compared to regular Rails partials
|
39
43
|
|
40
|
-
|
44
|
+
Consider this regular Rails partials rendering:
|
41
45
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
<br/>
|
46
|
+
```html+erb
|
47
|
+
<%= render "components/card" do %>
|
48
|
+
<% content_for :title, "Title content" %>
|
49
|
+
<% end %>
|
47
50
|
|
48
|
-
|
51
|
+
# app/views/components/_card.html.erb
|
52
|
+
<%= yield :title %>
|
53
|
+
<%= yield %>
|
54
|
+
```
|
55
|
+
|
56
|
+
There's a number of gotchas here:
|
49
57
|
|
58
|
+
- The `content_for` writes to `:title` across every partial, thus leaking.
|
59
|
+
- The rendering block isn't called until `<%= yield %>` is, so the `content_for` isn't called and `<%= yield :title %>` outputs nothing.
|
50
60
|
|
51
|
-
|
61
|
+
With Nice Partials the yield is automatic and we can write content for just that partial without leaking:
|
62
|
+
|
63
|
+
```html+erb
|
64
|
+
<%= render "components/card" do |partial| %>
|
65
|
+
<% partial.title "Title content" %>
|
66
|
+
<% end %>
|
67
|
+
|
68
|
+
# app/views/components/_card.html.erb
|
69
|
+
<%= partial.title %>
|
70
|
+
```
|
71
|
+
|
72
|
+
This happens because Nice Partials checks the partial source code for any `yield` calls that calls Rails' `capture` helper — e.g. `yield` and `yield something` but not `yield :title`. If there's no capturing yields Nice Partials calls `capture` for you.
|
73
|
+
|
74
|
+
This means Nice Partials also respect existing yield calls in your partial, so you can upgrade existing partials bit by bit or not at all if you don't want to.
|
52
75
|
|
53
76
|
Nice Partials:
|
54
77
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
78
|
+
- are still regular Rails view partials.
|
79
|
+
- reduces the friction when extracting components.
|
80
|
+
- only ends up in the specific partials you need the functionality.
|
81
|
+
- reduces context switching.
|
82
|
+
- allows isolated helper logic alongside your partial view code.
|
83
|
+
- doesn't require any upgrades to existing partials for interoperability.
|
84
|
+
- are still testable!
|
62
85
|
|
86
|
+
Nice Partials are a lightweight and more Rails-native alternative to [ViewComponent](http://viewcomponent.org). Providing many of the same benefits as ViewComponent with less ceremony.
|
63
87
|
|
64
|
-
##
|
88
|
+
## What extra powers does `partial` give me?
|
65
89
|
|
66
|
-
|
90
|
+
Having a `partial` object lets us add abstractions that are hard to replicate in standard Rails partials.
|
91
|
+
|
92
|
+
### Passing content from the render call
|
93
|
+
|
94
|
+
Nice Partials will use Action View's `local_assigns`, which stores any `locals` passed to `render`, as the basis for contents.
|
95
|
+
|
96
|
+
Given a partial like
|
67
97
|
|
68
98
|
```html+erb
|
69
|
-
|
70
|
-
|
71
|
-
<% content_for :image, flush: true do '' end %>
|
72
|
-
<div class="card-body">
|
73
|
-
<h5 class="card-title"><%= title %></h5>
|
74
|
-
<% if content_for? :body %>
|
75
|
-
<p class="card-text">
|
76
|
-
<%= yield :body %>
|
77
|
-
<% content_for :body, flush: true do '' end %>
|
78
|
-
</p>
|
79
|
-
<% end %>
|
80
|
-
</div>
|
81
|
-
</div>
|
99
|
+
<%# app/views/components/_card.html.erb %>
|
100
|
+
<%= partial.title %> written by <%= partial.byline %>
|
82
101
|
```
|
83
102
|
|
84
|
-
|
103
|
+
Can then be used like this:
|
85
104
|
|
86
|
-
|
105
|
+
```html+erb
|
106
|
+
<%= render "components/card", title: "Hello there", byline: "Some guy" do |partial| %>
|
107
|
+
<% partial.byline ", who writes stuff" %>
|
108
|
+
<% end %>
|
109
|
+
```
|
87
110
|
|
111
|
+
This will then output "Hello there written by Some guy, who writes stuff"
|
88
112
|
|
89
|
-
|
113
|
+
You can also use `slice` to pass on content from an outer partial:
|
90
114
|
|
91
|
-
|
115
|
+
```html+erb
|
116
|
+
<%= render "components/card", partial.slice(:title, :byline) %>
|
117
|
+
```
|
92
118
|
|
93
|
-
|
94
|
-
|
119
|
+
### Appending content from the view into a section
|
120
|
+
|
121
|
+
Nice Partials supports calling any method on `ActionView::Base`, like the helpers shown here, and then have them auto-append to the section.
|
122
|
+
|
123
|
+
```html+erb
|
124
|
+
<%= render "components/card" do |partial| %>
|
125
|
+
<% partial.title.t ".title" %>
|
126
|
+
<% partial.body.render "form", tangible_thing: @tangible_thing %>
|
127
|
+
<% partial.image.image_tag image_path("example.jpg"), alt: "An example image" %>
|
128
|
+
<% end %>
|
129
|
+
```
|
130
|
+
|
131
|
+
### I18n: translating and setting multiple keys at a time
|
132
|
+
|
133
|
+
`partial.t` is a shorthand to translate and assign multiple keys at once:
|
134
|
+
|
135
|
+
```html+erb
|
136
|
+
<% partial.t :title, description: :header, byline: "custom.key" %>
|
137
|
+
|
138
|
+
# The above is the same as writing:
|
139
|
+
<% partial.title t(".title") %>
|
140
|
+
<% partial.description t(".header") %>
|
141
|
+
<% partial.byline t("custom.key") %>
|
142
|
+
```
|
143
|
+
|
144
|
+
### Capturing options in the rendering block and building HTML tags in the partial
|
145
|
+
|
146
|
+
You can pass keyword options to a writer method and they'll be auto-added to `partial.x.options`, like so:
|
147
|
+
|
148
|
+
```html+erb
|
149
|
+
<%= render "components/card" do |partial| %>
|
150
|
+
<% partial.title "Title content", class: "text-m4", data: { controller: "title" } %>
|
151
|
+
<% end %>
|
152
|
+
|
153
|
+
# app/views/components/_card.html.erb:
|
154
|
+
# From the render above `title.options` now contain `{ class: "text-m4", data: { controller: "title" } }`.
|
155
|
+
# The options can be output via `<%=` and are automatically run through `tag.attributes` to be converted to HTML attributes.
|
156
|
+
|
157
|
+
<h1 <%= partial.title.options %>><%= partial.title %></h1> # => <h1 class="text-m4" data-controller="title">Title content</h1>
|
158
|
+
```
|
159
|
+
|
160
|
+
`partial` also supports auto-generating an element by calling any of Rails' `tag` methods e.g.:
|
161
|
+
|
162
|
+
```html+erb
|
163
|
+
# This shorthand gets us the same h1 element from the previous example:
|
164
|
+
<%= partial.title.h1 %> # => <h1 class="text-m4" data-controller="title">Title content</h1>
|
165
|
+
|
166
|
+
# Internally, this is similar to doing:
|
167
|
+
<%= tag.h1 partial.title.to_s, partial.title.options %>
|
95
168
|
```
|
96
169
|
|
97
|
-
|
170
|
+
### Yielding tag builders into the rendering block
|
98
171
|
|
99
|
-
|
172
|
+
The above example showed sending options from the rendering block into the partial and having it construct elements.
|
100
173
|
|
101
|
-
|
174
|
+
But the partial can also prepare tag builders that the rendering block can then extend and finalize:
|
102
175
|
|
103
|
-
|
176
|
+
```html+erb
|
177
|
+
<% render "components/card" do |partial|
|
178
|
+
<% partial.title { |tag| tag.h1 "Title content" } %>
|
179
|
+
<% end %>
|
104
180
|
|
105
|
-
|
181
|
+
# app/views/components/_card.html.erb
|
182
|
+
<% partial.title.yield tag.with_options(class: "text-m4", data: { controller: "title" }) %> # => <h1 class="text-m4" data-controller="title">Title content</h1>
|
183
|
+
```
|
106
184
|
|
107
|
-
###
|
185
|
+
### Smoother conditional rendering
|
108
186
|
|
109
|
-
|
187
|
+
In regular Rails partials it's common to see `content_for?` used to conditionally rendering something. With Nice Partials we can do this:
|
110
188
|
|
111
189
|
```html+erb
|
112
|
-
<%
|
190
|
+
<% if partial.title? %>
|
191
|
+
<% partial.title.h1 %>
|
192
|
+
<% end %>
|
113
193
|
```
|
114
194
|
|
115
|
-
|
195
|
+
But since sections respond to and leverage `present?`, we can shorten the above to:
|
116
196
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
- `yield p = np` ensures the developer using this partial also has a reference to that object, so they can define what goes in the various content buffers.
|
197
|
+
```html+erb
|
198
|
+
<% partial.title.presence&.h1 %>
|
199
|
+
```
|
121
200
|
|
122
|
-
|
201
|
+
This way no empty h1 element is rendered.
|
123
202
|
|
124
|
-
|
203
|
+
### Accessing the content returned via `partial.yield`
|
125
204
|
|
205
|
+
To access the inner content lines in the block here, partials have to manually insert a `<%= yield %>` call.
|
126
206
|
|
127
|
-
|
207
|
+
```html+erb
|
208
|
+
<%= render "components/card" do %>
|
209
|
+
Some content!
|
210
|
+
Yet more content!
|
211
|
+
<% end %>
|
212
|
+
```
|
213
|
+
|
214
|
+
With Nice Partials, `partial.yield` returns the same content:
|
215
|
+
|
216
|
+
```html+erb
|
217
|
+
# app/views/components/_card.html.erb
|
218
|
+
<%= partial.yield %> # => "Some content!\n\nYet more content!"
|
219
|
+
```
|
220
|
+
|
221
|
+
### Referring to the outer partial while rendering another
|
222
|
+
|
223
|
+
During a rendering block `partial` refers to the outer partial, so you can compose them.
|
224
|
+
|
225
|
+
```html+erb
|
226
|
+
<% partial.title "Title content" %>
|
227
|
+
|
228
|
+
<%= render "components/card" do |cp| %>
|
229
|
+
<% cp.title partial.title %>
|
230
|
+
<% end %>
|
231
|
+
```
|
128
232
|
|
129
|
-
|
233
|
+
### Passing content from one partial to the next
|
234
|
+
|
235
|
+
If you need to pass content into another partial, `content_from` lets you pass the keys to extract and then a hash to rename keys.
|
130
236
|
|
131
237
|
```html+erb
|
132
|
-
|
238
|
+
<%= render "components/card" do |cp| %>
|
239
|
+
<% cp.content_from partial, :title, byline: :header %>
|
240
|
+
<% end %>
|
241
|
+
```
|
242
|
+
|
243
|
+
Here, we copied the `partial.title` to `cp.title` and `partial.byline` became `cp.header`.
|
244
|
+
|
245
|
+
### Defining and using well isolated helper methods
|
246
|
+
|
247
|
+
If you want to have helper methods that are available only within your partials, you can call `partial.helpers` directly:
|
133
248
|
|
249
|
+
```html+erb
|
250
|
+
# app/views/components/_card.html.erb
|
251
|
+
<% partial.helpers do
|
134
252
|
# references should be a link if the user can drill down, otherwise just a text label.
|
135
253
|
def reference_to(user)
|
136
254
|
# look! this method has access to the scope of the entire view context and all the other helpers that come with it!
|
@@ -140,17 +258,30 @@ To minimize the amount of pollution in the global helper namespace, you can use
|
|
140
258
|
object.name
|
141
259
|
end
|
142
260
|
end
|
143
|
-
|
144
261
|
end %>
|
262
|
+
|
263
|
+
# Later in the partial we can use the method:
|
264
|
+
<td><%= partial.reference_to(user) %></td>
|
145
265
|
```
|
146
266
|
|
147
|
-
|
267
|
+
## Sponsored By
|
268
|
+
|
269
|
+
<a href="https://bullettrain.co" target="_blank">
|
270
|
+
<img src="https://github.com/CanCanCommunity/cancancan/raw/develop/logo/bullet_train.png" alt="Bullet Train" width="400"/>
|
271
|
+
</a>
|
272
|
+
<br/>
|
273
|
+
<br/>
|
274
|
+
|
275
|
+
> Would you like to support Nice Partials development and have your logo featured here? [Reach out!](http://twitter.com/andrewculver)
|
148
276
|
|
149
|
-
```html+erb
|
150
|
-
<td><%= p.reference_to(user) %></td>
|
151
|
-
```
|
152
277
|
|
153
|
-
##
|
278
|
+
## Setup
|
279
|
+
|
280
|
+
Add to your `Gemfile`:
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
gem "nice_partials"
|
284
|
+
```
|
154
285
|
|
155
286
|
### Testing
|
156
287
|
|
@@ -160,4 +291,4 @@ bundle exec rake test
|
|
160
291
|
|
161
292
|
## MIT License
|
162
293
|
|
163
|
-
Copyright (C)
|
294
|
+
Copyright (C) 2022 Andrew Culver <https://bullettrain.co> and Dom Christie <https://domchristie.co.uk>. Released under the MIT license.
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# # #
|
2
2
|
# Get gemspec info
|
3
3
|
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
|
4
6
|
gemspec_file = Dir["*.gemspec"].first
|
5
7
|
gemspec = eval File.read(gemspec_file), binding, gemspec_file
|
6
8
|
info = "#{gemspec.name} | #{gemspec.version} | " \
|
@@ -26,12 +28,3 @@ desc "#{gemspec.name} | IRB"
|
|
26
28
|
task :irb do
|
27
29
|
sh "irb -I ./lib -r #{gemspec.name.gsub '-','/'}"
|
28
30
|
end
|
29
|
-
|
30
|
-
# # #
|
31
|
-
# Run specs
|
32
|
-
|
33
|
-
desc "#{gemspec.name} | Test"
|
34
|
-
task :test do
|
35
|
-
sh "for file in test/*_test.rb; do ruby $file; done"
|
36
|
-
end
|
37
|
-
task default: :test
|