jensljungblad / elemental_components

Simple view components for Rails 5.1+
MIT License
76 stars 5 forks source link

Support validations for component attributes and elements #27

Closed msalzburg closed 5 years ago

msalzburg commented 5 years ago

We used the components gem in one of our recent web projects and really enjoyed it :)

To ensure the correct usage of our components we decided to "integrate" rails validations. Now invalid components will raise validations errors which can be detected by feature specs.

This behaviour is currently enabled for all environments, probably it should be configurable for each environment.

Obviously this is still work in progress - I am just wondering if you would consider merging it?

jensljungblad commented 5 years ago

Good to hear you've found it enjoyable :)

Yes I think validations are an excellent addition. I had a required option in the past that could be passed to attributes, but I think leveraging Rails validations is a better idea, since you can validate so much more than just presence.

As for how to do it.. Leaving it up to the user to implement in their ApplicationComponent initially sounded pretty good to me. It could have been documented similar to what you have in this PR and looked something like:

class ApplicationComponent < Components::Component
  include ActiveModel::Validations

  def initialize
    super
    validate!
  end

However, this only allows for validation of component attributes, and not of nested element attributes.

So that leaves either a) making it possible for the user to easily extend not only the base component, but the base element or b) include validations by default on Components::Element.

Have you thought of any issues with always including validations? There is already a dependency on Rails, so I wouldn't mind leveraging parts of ActiveModel, if it's for a good reason.

imathis commented 5 years ago

I've been working on implementing Components as well. I really like what you're doing here, but I too wish elements could extend other element classes. I was thinking about making a change to the elements class definition as follows:

def self.element(name, multiple: false, klass: Element, &config)
  plural_name = name.to_s.pluralize.to_sym if multiple

  elements[name] = {
    multiple: plural_name || false, class: Class.new(klass, &config)
  }
…

Which would allow me to create an element from a base class:

class MyComponent < Components::Component
  element :header, klass: MyHeaderElement
end
jensljungblad commented 5 years ago

@imathis Seems like a nice solution! This is mostly to avoid having to define methods etc in the block? Or to share methods among many elements?

imathis commented 5 years ago

@jensljungblad Having to treat each component and its elements as new creations doesn't work with my use case as well, so I'm working on making it possible to extend Elements and Components, allowing them to inherit elements, attributes, and methods, as well as allowing elements to render from templates. I'm not sure if that's something you're interested in or not, but I'd be happy to show you what I'm working on once I have it up and running.

msalzburg commented 5 years ago

Have you thought of any issues with always including validations? There is already a dependency on Rails, so I wouldn't mind leveraging parts of ActiveModel, if it's for a good reason.

@jensljungblad I like your thinking! Including it by default is no big pain and it makes the experience way better.

msalzburg commented 5 years ago

@jensljungblad I updated the branch accordingly. It should be mergeable now?

msalzburg commented 5 years ago

@imathis since this PR focuses on general component validation and is potentially done, maybe we should open a separate branch/pr for your element enhancement?

msalzburg commented 5 years ago

Except of the "nested_block" naming issue all comments should be resolved. How should we proceed?

msalzburg commented 5 years ago

Everything fine?

jensljungblad commented 5 years ago

Do we want to support validating the presence of elements? Is that a use case you've come across? I suppose then that validation would have to be moved to the render stage, since the elements are added after initialization.

class CardComponent
  element :header
  element :body
  element :footer

  validates :body, presence: true
end
msalzburg commented 5 years ago

Element presence validation already works ;) But I also added some tests.

Guess this branch is finally mergeable and we will continue in #32

jensljungblad commented 5 years ago

@msalzburg Haha right, because we yield the block before we run validate!.. Excellent :)

jensljungblad commented 5 years ago

@msalzburg Thanks for the contribution, great work!