Skip to content

Add support for conditional values to TagBuilder#37872

Merged
tenderlove merged 3 commits intorails:masterfrom
joelhawksley:content-tag-hash-class-conditional
Dec 4, 2019
Merged

Add support for conditional values to TagBuilder#37872
tenderlove merged 3 commits intorails:masterfrom
joelhawksley:content-tag-hash-class-conditional

Conversation

@joelhawksley
Copy link
Copy Markdown
Contributor

@joelhawksley joelhawksley commented Dec 3, 2019

This PR adds support for conditional values to TagBuilder,
extracting logic we use in the GitHub application,
inspired by https://github.com/JedWatson/classnames.

It’s common practice to conditionally apply CSS classes
in Rails views. This can lead to messy string interpolation,
often using ternaries:

content_tag(
  "My username",
  class: "always #{'sometimes' if current_user.special?} another"
)

By adding support for hashes to TagBuilder, we can instead write the following:

content_tag(
  "My username",
  class: ["always", "another", { 'sometimes' => current_user.special? }]
)

cc @JedWatson

Adds support for conditional values to TagBuilder,
extracting logic we use in the GitHub application,
inspired by https://github.com/JedWatson/classnames.

It’s common practice to conditionally apply CSS classes
in Rails views. This can lead to messy string interpolation,
often using ternaries:

```ruby
content_tag(
  "My username",
  class: "always #{'sometimes' if current_user.special?} another"
)
```

By adding support for hashes to TagBuilder, we can instead write the following:

```ruby
content_tag(
  "My username",
  class: ["always", "another", { 'sometimes' => current_user.special? }]
)
```

cc @JedWatson
@rails-bot rails-bot Bot added the actionview label Dec 3, 2019
Copy link
Copy Markdown
Member

@tenderlove tenderlove left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes a lot of sense for CSS classes. Should it be applied to all options though?

@joelhawksley
Copy link
Copy Markdown
Contributor Author

@tenderlove this probably doesn't make much sense for values to arguments besides class 👍

@tenderlove tenderlove merged commit 8c121ce into rails:master Dec 4, 2019
@joelhawksley joelhawksley deleted the content-tag-hash-class-conditional branch December 4, 2019 19:52
Edouard-chin added a commit to Edouard-chin/rails that referenced this pull request Dec 9, 2019
- rails#37872 introduced a regression and you can't do

  ```html.erb
    hidden_field_tag('token', value: [1, 2, 3])
  ```

  This will result in a `<input type="hidden" value=""`>.

  I chose `hidden_field_tag` and the `value` attribute as an example
  but this issue applies to any tag helper and any attributes.

  rails#37872 (comment)
  mention that the feature should only apply for "class" attribute.

  This commit fix original intent of rails#37872
@nashbridges
Copy link
Copy Markdown

This can lead to messy string interpolation,

For honest comparison with the new version, one could use arrays (that were already supported) + pure Ruby

content_tag(
  "My username",
  class: ["always", "another", ("sometimes" if current_user.special?)]
)

vs

content_tag(
  "My username",
  class: ["always", "another", { 'sometimes' => current_user.special? }]
)

Probably, the hash notation was inspired by JS Classnames library. Because in JS something like

[1, 2, (if (true) { 3 })]

is not only ugly, but also an invalid syntax.

@kenn
Copy link
Copy Markdown
Contributor

kenn commented Dec 28, 2019

@nashbridges I guess this API has parity with #37918 in mind.

@joelhawksley
Copy link
Copy Markdown
Contributor Author

@nashbridges - @kenn is correct. This PR was meant to enable #37918.

@nashbridges
Copy link
Copy Markdown

@kenn @joelhawksley I see, thanks guys!

On our project we use slim, so the class_names equivalent would be

.wrapper class=("active" if item.for_sale?)

but yeah, I can see that for ERB users the result is much more cleaner.

inopinatus added a commit to inopinatus/rails that referenced this pull request Feb 19, 2020
Taking the ideas introduced in rails#37872 and rails#37918, eliminating the use of
a switch-on-class, and generalising the production of tags to any context.
Passes an accumulator/result array to minimise allocations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants