-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for mocking a form builder objects #40
base: master
Are you sure you want to change the base?
Conversation
|
||
test "form stubs" do | ||
component = MountainView::Component.new("form_custom_button") | ||
presenter = FormCustomButtonComponent.new("form_custom_button", component.component_stubs.first) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [100/80]
39a68db
to
51d7d76
Compare
@drakmail thank you very much for the contribution! Will be checking the PR soon. |
Hi @drakmail, thanks for your contribution! I'm just curious if checking for |
@kitop Yes, I'm agree that it's a weak spot of current solution. There are an alternative way: create an internal proxy object for usage with forms (something like But there is could be a problem with forms that depends on a model methods, which couldn't be mocked by Hm, I get a good idea – maybe it's possible to use a convention for form builder names like Thanks for a good question, tomorrow I'll read a Psych gem sources more thoroughly and try to upgrade solution if it's possible. |
@drakmail thanks for your time! Can I be curious and ask if you are using MountainView on a production app? |
@kitop Yes, our company making a new app and we are decided to use MountainView as a foundation for our frontend because it fits really well in our workflow. PS. We are using rails 5 and MountainView doesn't have any compatibility problems with it :-) |
@drakmail awesome!!! Glad to hear that :) |
Hey guys - I've been thinking about this recently so thought I'd weigh in; feel free to ignore any or all of this! Ultimately I don't think trying to mock a formbuilder is going to work for every edge case. As @kitop says, there's just too many edge cases and they can be really complex. I do think you're on the right lines with your There would still be many edge cases presented; one off the top of my head is how you would pass a persisted ActiveRecord object since we would need to use I've kind of typed this as I was thinking it, so it may not make any sense, but let me know what you guys think! |
@tombeynon Nice idea, but seems that I found a simpler solution (as I think 😄): I want to add MountainView::Helpers module with FormFor class, which could be used to mock form builder for a specific model with a specific attributes. Example of :meta: 'There is a class with form builder object'
:stubs:
-
:id: 1
:form:
!ruby/object:MountainView::Helpers::FormBuilder # generates form builder stub with passed `Something` model
model: !ruby/object:Something
attributes:
name: 'something name' And now it's possible to pass any ruby objects (including AR models) without any conflicts with form builders. For example, I could pass an any AR model with preinitialized fields like this: :meta: 'There is a class with form builder object'
:stubs:
-
:id: 1
:some_model: !ruby/object:Something
attributes:
id: 14
name: 'blabla' |
@drakmail I guess my only problem with that is that you've had to create a stub class for a FormBuilder. That's great for this instance, but what if you're not working with forms, but some other complex object? My problem with only using the YAML file is that we can't use any ruby code to build the stub, and that will eventually restrict us. Using the route you've suggested I expect a LOT of work would end up going into creating stub classes for all the different use cases. What do you think? |
@tombeynon hm, but with
|
I think I follow; I totally agree that :meta: 'There is a class with form builder object'
:stubs:
-
:id: 1
:some_model: !ruby/object:Something
attributes:
id: 14
name: 'blabla' render_component 'whatever', {id: 1, some_model: Something.new({id: 14, name: 'blabla'})} I just think instead of going down the route of providing :meta: 'There is a class with custom stub object'
:stubs:
-
:id: 1
:some_model:
attributes:
id: 14 class WhateverStub < MountainView::Stub
include ActionView::Helpers::FormHelper
def initialize(properties={}) # this would be defined in MountainView::Stub
@properties = properties
end
def stubs
{
id: 1,
form: form
}
end
def form
form_for(some_model)
end
def some_model
Something.find(properties[:some_model][:attributes][:id])
end
end render_component 'whatever', {id: 1, form: form} Thinking out loud still, looking forward to your thoughts. |
@tombeynon oh, I got it. The idea is very close to what I implemented. But seems that But I doesn't see any disadvantages for component stubbing with providing custom stub class, preinitialized AR model or form builder stub like that (part of README.md for new functionality): Setting up the style guide
mount MountainView::Engine => "/mountain_view"
E.g: -
:title: "Aspen Snowmass"
:description: "Aspen Snowmass is a winter resort complex located in Pitkin County in western Colorado in the United States. Owned and operated by the Aspen Skiing Company it comprises four skiing/snowboarding areas on four adjacent mountains in the vicinity of the towns of Aspen and Snowmass Village."
:link: "http://google.com"
:image_url: "http://i.imgur.com/QzuIJTo.jpg"
:data:
-
:title: "Elevation"
:number: '7879ft'
-
:title: "Depth"
:number: '71"'
-
:title: "Sunset on the Mountain"
:description: "Three major ranges of the Alps – the Northern Calcareous Alps, Central Alps, and Southern Calcareous Alps – run west to east through Austria. The Central Alps, which consist largely of a granite base, are the largest and highest ranges in Austria."
:link: "http://google.com"
If your component depends on a form builder object you can use the following statement: :meta: 'There is a class with form builder object'
:stubs:
-
:form:
!ruby/object:MountainView::Helpers::FormBuilder
model: !ruby/object:Something
attributes:
name: 'something name' Also you can stub any ruby class with the following method: :meta: 'There is a class with an AR object'
:stubs:
-
:some_model: !ruby/object:Something
attributes:
name: 'blabla' For any complex logic you can define a custom Compoenent Stub with :meta: 'There is a class with a complex logic'
:stubs:
-
:some_model: !ruby/object:ComponentStub
params:
- 'blabla'
- 'nothing'
name: 'Some Name' class ComponentStub < SomeModel # SomeModel could be AR class
def init_with(coder)
param1 = coder.map["params"].first
somename = coder.map["name"]
# or `@properties = coder.map`
initialize(param1, somename) # call initializer of SomeModel
end
end |
def create_form_builder(model) | ||
initialize(model.class.model_name.param_key, model, ActionView::Base.new, {}) | ||
rescue | ||
initialize(model.class.model_name.param_key, model, ActionView::Base.new, {}, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [90/80]
@tombeynon thanks for joining the discussion! Very helpful additions :) @drakmail thanks for updating the PR. Something else to look for is how the styleguide is displayed after this change: Right now it displays Having a Thoughts? |
@kitop Thanks for feedback! I agree that I think it's possible to override displaying of complex objects, it's very good idea. I think, it basically could be something like
I'll try to implement it today |
I did a small research and found that it's possible to add custom domain models for Psych parser. So, now it's possible to change syntax to this: :meta: 'There is a class with form builder object'
:stubs:
-
:id: 1
:some_model: !mountain_view:Model # declaration with domain (`mountain_view`) inclusion
class: Something # it's possible to use any custom DSL here, i think usage of `class` and `attributes` is a good variant
attributes:
name: 'blabla'
:some_another_model: !Model # it's also possible to use shorter syntax
class: Something
attributes:
name: 'blabla'
:form:
!Form # It's a form builder declaration
for: !Model # for model defined in DSL that was introduced early, best part that it's possible (potentially) any custom params to form for
class: Something
attributes:
name: 'something name' This approach allows to define custom wrappers for models (and POROs) for generating pretty PS. Maybe better name object declaration not a |
|
||
def to_json(_) | ||
object = __getobj__ | ||
"#{object.class.model_name}.new(#{object.attributes.delete_if { |k, v| v.nil? }.deep_symbolize_keys})" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused block argument - k
. If it's necessary, use _
or _k
as an argument name to indicate that it won't be used.
Line is too long. [110/80]
e93dbea
to
458c863
Compare
I'm updated PR to use new syntax for objects and forms. Example of :meta: 'information about the component button' # Optional
:stubs: # As many as you need
-
:title: "Small danger button"
:size: "small"
:color: "dng"
:user: !Object
class: User::Corporate
attributes:
email: "[email protected]"
:form: !Form
for: !Object
class: User
attributes:
email: "[email protected]" Generated Styleguide: |
@@ -0,0 +1,22 @@ | |||
require 'delegate' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Hey guys, My team is brand-new to MountainView (ps - ❤️ - this is an amazing gem) - but this is a problem we're very interested in learning more about recommended solutions for. We're using it quite a bit with SimpleForm to create reusable form components, and don't see any clean paths forward for mocking the form builders. Is this something that's actively being pursued still, or is it more or less abandoned at this point? With the last commits on master showing as over a year ago, just want to make sure we're looking in the right direction. Rob |
Hi @robcole thanks for you nice words! This is not abandoned at all, but it is not a trivial problem to solve and we'd like to arrive to a nice solution to it. Any feedback, comments, tips, etc, are more than welcomed! Having said that, yesterday we released a new version with a feature that may help with this: #49 (shoutout to @MikeRogers0 for the amazing work!). With this, you may be able to pass the form in a block to a component, and stub it (or at least a placeholder) in the styleguide view with the Does that help? Happy to discuss and keep looking for a nice way to solve this issue. |
@kitop Thanks for the response! I'll start digging into the block-based approach and see if I can find some clarity for how our team handles this, and (possibly) see if I can help contribute to a more generalizable solution. Just wanted to make sure this PR was still active as a "we intend solve this hard problem someday when we figure out a solution we like" sort of PR, since the discussion was quite old. |
@robcole thanks for understanding!! |
@kitop I've read through the PR that brings in block support for components as well as the discussion for how stubs might work using it, but didn't see any clear resolution in the PR or in the current docs for how you might stub an object that's being passed to yield. Let me know if you have any additional info that might clarify what you were thinking / how you suggest working with that. Thanks! |
@robcole We didn't come to a resolution, what I've been doing in my current projects styleguide is:
I'm all ears for a better solution though! |
@robcole as @MikeRogers0 said, we didn't come to a resolution when mocking You can either do as @MikeRogers0 suggested, or also use the Any feedback will be greatly appreciated! |
As a @tombeynon commented in a #26 it's not possible to generate Styleguides for components that need a form builder instance. In this PR I try to implement a possible solution for that issue. Now it's possible to pass in stubs config an ActiveRecord based class which will be used for mocking a form_builder need for component.
For example: if a component need a
form
parameter (which is must be an instance of Form Builder for, for example,Something
model), now it's possible to mock it in stubs file like this: