Why we’re dasherizing Ruby symbols in v2 #785
Replies: 2 comments 5 replies
-
We can mostly adapt to this, but one scenario that's frustrating is Stimulus or other front-end/back-end communication, where we're specifically looking to match symbol values. Sometimes we do stuff like: class SomeController < ApplicationController
def edit
...
end
def update
params.fetch(param_key)
end
private
def param_key = :a_symbol
end
class Views::Edit < Phlex::HTML
def view_template
div(data: { controller: "some-controller", some_param_value: helpers.param_key })
...
end
end
end No so different from the Overriding would be fine if it were easy, but as it stands, we'd have to override Luckily (thanks to @joeldrapper), we have a lot of |
Beta Was this translation helpful? Give feedback.
-
What do you think about? when Symbol
buffer << " " << name << '="' << process_symbol_attribute_value(v) << '"'
...
def process_symbol_attribute_value(value)
value.name.tr("_", "-").gsub('"', """)
end It would be easy to override the behavior without having to override the entire That said, I think symbol should not dasharized by default when used as attribute value, at least, not in Phlex::Rails, because it is how Rails works and it is the expected behavior when you are using something that integrates with Rails. Now it is causing some overhead to remember the incompatibilities, eg. div id: :foo_bar # => <div id="foo-bar">
turbo_frame_tag :foo_bar #=> <turbo-frame id="foo_bar">
turbo_stream.replace(:foo_bar, ...) # it don't work with "div id: :foo_bar". |
Beta Was this translation helpful? Give feedback.
-
SGML (HTML and SVG) has a few different data types, most of which are encoded in what can look like literal string syntax.
Booleans
Not to be confused with enumerated tokens, boolean attributes are only encoded as a valueless attribute when true. Otherwise they are considered to be false.
Integer
The attributes
cols
androws
on a<textarea>
while encoded as literal strings are really integers.Floats
Likewise, the attributes
cx
,cy
andr
on a<circle>
are floats.Strings
While every type is encoded as a literal string there are some true strings, such as
value
on an<input>
. This is obviously meant to be an exact list of bytes.Enumerated tokens
Some attributes support a specific enumeration of tokens: For example, the
type
attribute on an<input>
must match a specific token —text
,checkbox
,datetime-local
, etc.Token lists
Some attributes support a whitespace separated list of tokens — either enumerated or free-form. The
autocomplete
attribute on an<input>
is a good example of an enumerated token list. Theclass
attribute is an example of a free-form token list.Tokens
We’ve already seen enumerated tokens and token lists — these must both depend on some concept of a token type. These can be tricky to distinguish from strings and I admit the line is definitely blurred but I think tokens serve a purpose quite distinct from strings.
The attribute
id
, orname
on an<input>
come to mind as sort of free-form tokens. Yes, technically they’re the same as strings, but they have a distinct purpose to identify some concept with a unique symbol.It is a strong convention in HTML (and CSS) that each word in a multi-word token is separated with a single dash or hyphen (
-
). Not only is this convention universally applied to built in attributes, it is also adopted in all popular CSS frameworks.This brings us to Phlex.
Phlex
Phlex is trying to bridge the gap between Ruby and HTML, allowing you to express HTML semantics in the Ruby language.
Phlex has to do a best-effort job of bridging this gap — HTML tags are methods, attributes are keyword arguments, content is passed as a block. It also has to try to adapt Ruby types to HTML types. Ruby boolean values
true
andfalse
correspond to boolean attributes. Ruby Arrays and Sets correspond to token lists. Strings are strings, obviously. Integers are integers and floats are floats.Now we come to Ruby’s built in Symbol type. In the same way you can technically put any character in an HTML token, you can technically put any character in a Ruby Symbol, e.g.
:"hello-there 'world'"
. But by convention, Ruby symbols are simple names for concepts, conventionally separated by underscores::font_bold
. You can convert Symbols to a string and you get a byte-for-byte string representation of the name, but you lose something in doing this. You lose the purpose of the symbol. The whole point of the symbol was to name some symbolic concept, not to store the bytes of a name, word delineators and all.We could use — and have historically used — this byte-for-byte string conversion when symbols were passed as values to HTML attributes in Phlex. However, this seems disingenuous. Ruby’s Symbol exactly matches the concept of an HTML token. The difference is the words in multi-word symbols are conventionally separated by an underscore (
_
) in Ruby while the words in multi-word tokens are conventionally separated by a dash (-
) in HTML.Because of this strong convention, I believe it is right to replace underscores with dashes when converting symbol values to HTML.
Where this might get annoying
Rails (being Rails) completely ignores the HTML convention followed by pretty much every other library in the world that interacts with HTML. By default, Rails’ form helpers output unconventional underscored input names, and the controllers that receive form submissions expect to find underscores on the other side.
This isn’t an issue if you’re using Rails’ form helpers —
form_with
,form_for
, etc. but if you’re building your own forms in Phlex, it might be a little annoying. My advice is to either handle this inconsistency in your form component — using strings instead of symbols for the names, or to fix the issue in the parameter parsing phase of the controller.As annoying as it may be, this is an area where Rails got it wrong. Phlex does not depend on Rails and will not be broken by it.
Why can’t you patch or configure Phlex to behave differently?
Technically you can. You could override
__attributes__
converting all symbols to strings and passing them up tosuper
. But Phlex uses a global attributes cache so doing this could break other libraries that depend on Phlex such as component kits you install, or other gems with web interfaces.Beta Was this translation helpful? Give feedback.
All reactions