ageweke / fortitude Goto Github PK
View Code? Open in Web Editor NEWViews Are Code: use all the power of Ruby to build views in your own language.
License: MIT License
Views Are Code: use all the power of Ruby to build views in your own language.
License: MIT License
On startup of our app a large amount of widgets are loaded immediately (asset aggregator :)), this has the side effect of causing the needs to be built up front. It adds about an extra minute to start up time to our app.
I added some basic annotation which prints whenever rebuild_my_needs_methods!
is called, I noticed things like this:
...
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
Called rebuild_my_needs_methods! on Views::Profiles::Show
...
Seems like there's definitely something wrong here, it appears to be redefining the methods many times over for a single widget on a large percentage of them.
Other possible things to investigate:
Can we defer needs creation until widget is used at lease once.
I noticed your simple templating language doesn't cache the templates and re-parses every time it's executed.
Maybe I'm doing something wrong or reading the spec wrong, but AFAICT, special characters do not have to be HTML-escaped when inside of attribute values.
Here's Erector:
And here's Fortitude:
This came up because we were rendering a <script type='text/template'>
element, and were using underscore templates (<%= variable_name >
) inside of a href=""
attribute.
Also, this might be an issue for data-*
attributes where there may be special characters that hook into Javascript plugins?
This is kind of a bizarre case, not sure what the correct approach is. This would allow you to have some method in your widget that returns deep within html builder blocks and still have valid markup rendered.
def some_widget_method
dt class: "hello" do
p "Yes please"
return
end
end
Erector:
<dt class="hello"><p>Yes please</p></dt>
Fortitude:
<dt class="hello"><p>Yes please</p>
The static method only seems to work if a super class defines it.
For example,
Views:: Base
def main
end
Views::Layouts::Page < Views::Base
static :main
static :intro
def main
end
def intro
end
This will result in undefined method `intro'
I wrote this caching module for erector-rails4, which adds all of the neat cache_digests stuff to widgets. What's even cooler about using cache_digests in Erector is that because your needs are explicit, you can calculate the cache_key
for a widget without having to manually specify the objects it depends on.
Is this something you'd be interested in implementing in fortitude? Anything about the implementation that you'd want to change?
...probably I'm just having even more of a brain-dead week than usual. (Yes, I have read Issue #15, along with Issue #21 and tried to wrap my head around Commit 9d7ee0b that closed it, for what those are worth.)
Consider the following, in an otherwise thoroughly-vanilla Fortitude-fortified Rails app:
# Class encapsulating all page-specific view code for `things/new`.
class Views::Things::New < Views::Base
needs :thing, flash: {},
title_content: 'Add New Thing to List of All Things'
# include SemanticLogger::Loggable
include Fortitude::Rails::Helpers
def content
page_title_content
form_for(:thing) do |f|
end
end
private
def page_title_content
content_for :title, title_content
end
end # class Views::Things::New
Yet when I run a simple test that uses the class, form_for
is undefined:
$ bundle exec ruby -Itest test/views/things/new_test.rb
# Running tests with run options --seed 10623:
E
Error:
Views::Things::New#test_0001_calls the #content_for helper correctly when rendered:
NoMethodError: undefined method `form_for' for #<Object:0x007fb89a611d90>
app/views/things/new.rb:14:in `content'
test/views/things/new_test.rb:22:in `block (2 levels) in <main>'
test/views/things/new_test.rb:25:in `block (2 levels) in <main>'
Finished tests in 0.471040s, 2.1230 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
Test code:
require 'test_helper'
require File.expand_path('app/views/things/new', Rails.root)
describe 'Views::Things::New' do
let(:described_class) { Views::Things::New }
let(:flash) { ActionDispatch::Flash::FlashHash.new }
let(:thing) { FactoryGirl.build_stubbed :thing }
let(:obj) do
described_class.new(thing: thing, flash: flash).tap do |ret|
ret.class_eval do
attr_reader :cf_attrib, :cf_value
def ret.content_for(attrib, value)
@cf_attrib = attrib
@cf_value = value
end
end
end
end
let(:actual) { obj.to_html }
it 'calls the #content_for helper correctly when rendered' do
_ = actual # nothing happens until widget is rendered, so...
expect(obj.cf_attrib).must_equal :title
expect(obj.cf_value).must_equal 'Add New Thing to List of All Things'
end
end # describe 'Views::Things::New'
Line 14 of the source is, of course, the call to form_for
, and Line 22 of the test (mentioned in the backtrace) is the assignment to actual
which renders the widget (which is where you'd expect it to blow up, I guess). I've been beating my head against one variant or another of this for days; what am I missing (again)?
tried throwing this in an initializer and realized that I really don't know what's going on:
SIMPLE_FORM_FOR_YIELDED_METHODS_TO_OUTPUT =
# https://github.com/plataformatec/simple_form/blob/6c28bf483345678e22012e576a5ab0dc440d0724/lib/simple_form/form_builder.rb
%w{input attribute input_field association button error full_error hint label} +
%w{error_notification collection_radio_buttons collection_check_boxes}
Fortitude::Rails::Helpers.helper(
:simple_form_for,
transform: :output_return_value,
output_yielded_methods: SIMPLE_FORM_FOR_YIELDED_METHODS_TO_OUTPUT
)
Fortitude::Rails::Helpers.helper(
:simple_fields_for,
transform: :output_return_value,
output_yielded_methods: SIMPLE_FORM_FOR_YIELDED_METHODS_TO_OUTPUT
)
So I've actually looked for where this is documented in the Rails docs and can't find it, but given a route like this:
And if you have instance variables for @site
and @project
, you can call the route explicitly:
project_admin_responses_path(@site.id, @project.id)
Or you can leave out the arguments, and Rails will implicitly pass your instance variables to the route helper:
project_admin_responses_path
However, the change in d7eeec4 (which I don't quite understand in the first place) breaks this second syntax:
I think I understand why, but I'm wondering if this would be considered a regression, and if this is OK. I find it weird that you had to specify default_url_options
in d7eeec4#diff-c039a5faaa76d9264a41ffc542ef3a82R87, since Rails shouldn't need those when rendering views.
Thoughts?
When rendering with render widget: Views::MyWidget
I noticed that running capture
returns nil
and leaves the output on the existing output buffer. If I force _fortitude_builtin_capture
to run then it works.
Looking deeper, the rails implementation of capture uses this method:
def with_output_buffer(buf = nil) #:nodoc:
unless buf
buf = ActionView::OutputBuffer.new
buf.force_encoding(output_buffer.encoding) if output_buffer.respond_to?(:encoding) && buf.respond_to?(:force_encoding)
end
self.output_buffer, old_buffer = buf, output_buffer
yield
output_buffer
ensure
self.output_buffer = old_buffer
end
This works for the output buffer stored on helpers
, which is used by fortitude in a normal render. But with render :widget
we are rendering to string with our own internal fortitude output buffer, so this method doesn't have right effect.
Valid in erector:
div nil
text nil
rawtext nil
Erector just uses to_s
on nil
, converting it to empty string. Fortitude errors.
Also noticed this difference:
div class: nil
In Erector: <div></div>
In Fortitude <div class></div>
In the erector doc, you mention this:
Configure all options on a per-class basis with inheritance (zero "across-the-board" global settings);
I certainly understand why this is attractive, but maybe you can help me understand how to properly implement this use case:
html5
doctypestart_and_end_comments
, everFortitude::Widget
What's the best way to ensure that all of my components receive these options? Should I subclass Fortitude::Widget
to Fortitude::MyWidget
, that has my configuration applied? (Seems messy.) Should I apply my configuration directly to the Fortitude::Widget
? (This seems wrong.) Do I inherit from Fortitude::Widgets::Html5
? (Too many characters, doesn't have my config.)
Hey Andrew et al,
I'm the maintainer of the "modern" version of Erector, that you can find at https://github.com/ajb/erector-rails4/. We use Erector extensively at my company, and we couldn't be more excited that you're developing fortitude -- seems like you're keeping a lot of the great parts about Erector while ditching the weirder ones.
Anyway, this is more of a comment, less of a question, but whenever you have a structure in place to accept contributions, we're more than excited to start moving in the direction of using Fortitude.
Erector's Rails integration, IIRC, gave you a controller
accessor that you could call #flash
on to retrieve flash messages. I've been stumped for a full day on how to access flash messages inside a Fortitude page widget. What am I missing?
It would be cool if you could specify a list of needs that static
caching could vary on. For example we want to cache some widgets but we also render them in different locales, so it would be nice to say something like:
static :html_content, varies: [:locale]
or something similar. Then for each value of locale that the widget renders from would use a different cache
So I'm converting some Erector code to Fortitude. Outside of a normal ActionView context (say, in a model,) we've got a method that looks like this:
def to_table_cell(attachment_ids)
Erector.inline do
Attachment.find(attachment_ids).each do |attachment|
a attachment.upload.raw_filename,
href: download_attachment_path(attachment),
target: '_blank'
end
end.to_html
end # => "<a href="/attachment/12/download" target="_blank">myfile.jpg</a>"
I've noticed that Fortitude has an inline_html
method, to which you can pass a block. However, it appears that since we're outside of the ActionView context, we don't have access to the download_attachment_path
helper that Rails provides.
@ageweke: I've kept up a bit with the recent issue comments about rendering context... but I'm unsure if there's a way you'd recommend to implement this.
It looks like I could probably create an instance of ActionView::Base
and somehow use it as my rendering context. I could probably package it up in a nice little method that would be easy to call in the future. But I feel like I'm probably doing something wrong here...
I get this or similar stack trace on every test and every page render attempt. I attached my Gemfile too and am using ruby-2.3.0.
ArgumentError (wrong number of arguments (given 5, expected 4)):
fortitude (0.9.4) lib/fortitude/rails/railtie.rb:251:in find_templates_with_fortitude' actionview (4.2.5.2) lib/action_view/template/resolver.rb:116:in
block in find_all'
actionview (4.2.5.2) lib/action_view/template/resolver.rb:152:in block in cached' actionview (4.2.5.2) lib/action_view/template/resolver.rb:63:in
cache'
actionview (4.2.5.2) lib/action_view/template/resolver.rb:151:in cached' actionview (4.2.5.2) lib/action_view/template/resolver.rb:115:in
find_all'
actionview (4.2.5.2) lib/action_view/path_set.rb:70:in block (2 levels) in _find_all' actionview (4.2.5.2) lib/action_view/path_set.rb:66:in
each'
actionview (4.2.5.2) lib/action_view/path_set.rb:66:in block in _find_all' actionview (4.2.5.2) lib/action_view/path_set.rb:65:in
each'
actionview (4.2.5.2) lib/action_view/path_set.rb:65:in _find_all' actionview (4.2.5.2) lib/action_view/path_set.rb:54:in
find_all'
actionview (4.2.5.2) lib/action_view/path_set.rb:46:in find' actionview (4.2.5.2) lib/action_view/lookup_context.rb:121:in
find'
actionview (4.2.5.2) lib/action_view/renderer/abstract_renderer.rb:18:in find_template' actionview (4.2.5.2) lib/action_view/renderer/template_renderer.rb:40:in
determine_template'
actionview (4.2.5.2) lib/action_view/renderer/template_renderer.rb:8:in render' actionview (4.2.5.2) lib/action_view/renderer/renderer.rb:46:in
render_template'
actionview (4.2.5.2) lib/action_view/renderer/renderer.rb:27:in render' actionview (4.2.5.2) lib/action_view/rendering.rb:100:in
_render_template'
actionpack (4.2.5.2) lib/action_controller/metal/streaming.rb:217:in _render_template' actionview (4.2.5.2) lib/action_view/rendering.rb:83:in
render_to_body'
actionpack (4.2.5.2) lib/action_controller/metal/rendering.rb:32:in render_to_body' actionpack (4.2.5.2) lib/action_controller/metal/renderers.rb:37:in
render_to_body'
actionpack (4.2.5.2) lib/abstract_controller/rendering.rb:25:in render' actionpack (4.2.5.2) lib/action_controller/metal/rendering.rb:16:in
render'
actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:44:in block (2 levels) in render' activesupport (4.2.5.2) lib/active_support/core_ext/benchmark.rb:12:in
block in ms'
/Users/glenn/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/benchmark.rb:308:in realtime' activesupport (4.2.5.2) lib/active_support/core_ext/benchmark.rb:12:in
ms'
actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:44:in block in render' actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:87:in
cleanup_view_runtime'
activerecord (4.2.5.2) lib/active_record/railties/controller_runtime.rb:25:in cleanup_view_runtime' actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:43:in
render'
fortitude (0.9.4) lib/fortitude/rails/rendering_methods.rb:85:in render_with_fortitude' actionpack (4.2.5.2) lib/action_controller/metal/implicit_render.rb:10:in
default_render'
actionpack (4.2.5.2) lib/action_controller/metal/implicit_render.rb:5:in send_action' actionpack (4.2.5.2) lib/abstract_controller/base.rb:198:in
process_action'
actionpack (4.2.5.2) lib/action_controller/metal/rendering.rb:10:in process_action' actionpack (4.2.5.2) lib/abstract_controller/callbacks.rb:20:in
block in process_action'
activesupport (4.2.5.2) lib/active_support/callbacks.rb:117:in call' activesupport (4.2.5.2) lib/active_support/callbacks.rb:555:in
block (2 levels) in compile'
activesupport (4.2.5.2) lib/active_support/callbacks.rb:505:in call' activesupport (4.2.5.2) lib/active_support/callbacks.rb:92:in
run_callbacks'
activesupport (4.2.5.2) lib/active_support/callbacks.rb:778:in _run_process_action_callbacks' activesupport (4.2.5.2) lib/active_support/callbacks.rb:81:in
run_callbacks'
actionpack (4.2.5.2) lib/abstract_controller/callbacks.rb:19:in process_action' actionpack (4.2.5.2) lib/action_controller/metal/rescue.rb:29:in
process_action'
actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:32:in block in process_action' activesupport (4.2.5.2) lib/active_support/notifications.rb:164:in
block in instrument'
activesupport (4.2.5.2) lib/active_support/notifications/instrumenter.rb:20:in instrument' activesupport (4.2.5.2) lib/active_support/notifications.rb:164:in
instrument'
actionpack (4.2.5.2) lib/action_controller/metal/instrumentation.rb:30:in process_action' actionpack (4.2.5.2) lib/action_controller/metal/params_wrapper.rb:250:in
process_action'
activerecord (4.2.5.2) lib/active_record/railties/controller_runtime.rb:18:in process_action' actionpack (4.2.5.2) lib/abstract_controller/base.rb:137:in
process'
actionview (4.2.5.2) lib/action_view/rendering.rb:30:in process' actionpack (4.2.5.2) lib/action_controller/metal.rb:196:in
dispatch'
actionpack (4.2.5.2) lib/action_controller/metal/rack_delegation.rb:13:in dispatch' actionpack (4.2.5.2) lib/action_controller/metal.rb:237:in
block in action'
actionpack (4.2.5.2) lib/action_dispatch/routing/route_set.rb:74:in dispatch' actionpack (4.2.5.2) lib/action_dispatch/routing/route_set.rb:43:in
serve'
actionpack (4.2.5.2) lib/action_dispatch/journey/router.rb:43:in block in serve' actionpack (4.2.5.2) lib/action_dispatch/journey/router.rb:30:in
each'
actionpack (4.2.5.2) lib/action_dispatch/journey/router.rb:30:in serve' actionpack (4.2.5.2) lib/action_dispatch/routing/route_set.rb:815:in
call'
xray-rails (0.1.18) lib/xray/middleware.rb:38:in call' omniauth (1.3.1) lib/omniauth/strategy.rb:186:in
call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in call' omniauth (1.3.1) lib/omniauth/builder.rb:63:in
call'
meta_request (0.3.4) lib/meta_request/middlewares/app_request_handler.rb:13:in call' meta_request (0.3.4) lib/meta_request/middlewares/meta_request_handler.rb:13:in
call'
rack (1.6.4) lib/rack/etag.rb:24:in call' rack (1.6.4) lib/rack/conditionalget.rb:25:in
call'
rack (1.6.4) lib/rack/head.rb:13:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/params_parser.rb:27:in
call'
actionpack (4.2.5.2) lib/action_dispatch/middleware/flash.rb:260:in call' rack (1.6.4) lib/rack/session/abstract/id.rb:225:in
context'
rack (1.6.4) lib/rack/session/abstract/id.rb:220:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/cookies.rb:560:in
call'
activerecord (4.2.5.2) lib/active_record/query_cache.rb:36:in call' activerecord (4.2.5.2) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in
call'
activerecord (4.2.5.2) lib/active_record/migration.rb:377:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/callbacks.rb:29:in
block in call'
activesupport (4.2.5.2) lib/active_support/callbacks.rb:88:in __run_callbacks__' activesupport (4.2.5.2) lib/active_support/callbacks.rb:778:in
_run_call_callbacks'
activesupport (4.2.5.2) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.5.2) lib/action_dispatch/middleware/callbacks.rb:27:in
call'
actionpack (4.2.5.2) lib/action_dispatch/middleware/reloader.rb:73:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/remote_ip.rb:78:in
call'
airbrake (4.3.5) lib/airbrake/rails/middleware.rb:13:in call' rack-contrib (1.4.0) lib/rack/contrib/response_headers.rb:17:in
call'
meta_request (0.3.4) lib/meta_request/middlewares/headers.rb:16:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/debug_exceptions.rb:17:in
call'
web-console (3.1.1) lib/web_console/middleware.rb:131:in call_app' web-console (3.1.1) lib/web_console/middleware.rb:28:in
block in call'
web-console (3.1.1) lib/web_console/middleware.rb:18:in catch' web-console (3.1.1) lib/web_console/middleware.rb:18:in
call'
actionpack (4.2.5.2) lib/action_dispatch/middleware/show_exceptions.rb:30:in call' railties (4.2.5.2) lib/rails/rack/logger.rb:38:in
call_app'
railties (4.2.5.2) lib/rails/rack/logger.rb:20:in block in call' activesupport (4.2.5.2) lib/active_support/tagged_logging.rb:68:in
block in tagged'
activesupport (4.2.5.2) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.2.5.2) lib/active_support/tagged_logging.rb:68:in
tagged'
railties (4.2.5.2) lib/rails/rack/logger.rb:20:in call' quiet_assets (1.1.0) lib/quiet_assets.rb:27:in
call_with_quiet_assets'
actionpack (4.2.5.2) lib/action_dispatch/middleware/request_id.rb:21:in call' rack (1.6.4) lib/rack/methodoverride.rb:22:in
call'
rack (1.6.4) lib/rack/runtime.rb:18:in call' activesupport (4.2.5.2) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in
call'
rack (1.6.4) lib/rack/lock.rb:17:in call' actionpack (4.2.5.2) lib/action_dispatch/middleware/static.rb:116:in
call'
rack (1.6.4) lib/rack/sendfile.rb:113:in call' airbrake (4.3.5) lib/airbrake/user_informer.rb:16:in
_call'
airbrake (4.3.5) lib/airbrake/user_informer.rb:12:in call' railties (4.2.5.2) lib/rails/engine.rb:518:in
call'
railties (4.2.5.2) lib/rails/application.rb:165:in call' rack (1.6.4) lib/rack/content_length.rb:15:in
call'
puma (2.16.0) lib/puma/server.rb:557:in handle_request' puma (2.16.0) lib/puma/server.rb:404:in
process_client'
puma (2.16.0) lib/puma/server.rb:270:in block in run' puma (2.16.0) lib/puma/thread_pool.rb:106:in
block in spawn_thread'
Gemfile:
source 'https://rubygems.org'
ruby '2.3.0'
gem 'airbrake', '< 5'
gem 'coffee-rails'
gem 'compass-rails', '< 3'
gem 'ethereum'
gem 'faye-websocket'
gem 'fortitude'
gem 'foundation-icons-sass-rails'
gem 'foundation-rails', '< 6'
gem 'jbuilder'
gem 'jquery-rails'
gem "nilify_blanks"
gem 'nokogiri'
gem 'omniauth-slack'
gem 'omniauth'
gem 'pg'
gem 'postmark-rails'
gem 'premailer-rails'
gem 'puma'
gem 'pundit'
gem 'rails_12factor', group: :production
gem 'rails', '4.2.5.2'
gem "refile", require: "refile/rails"
gem "refile-mini_magick"
gem "refile-s3"
gem 'responders'
gem 'sass-rails'
gem 'sdoc', group: :doc
gem 'slack-ruby-client'
gem 'sucker_punch'
gem 'uglifier'
group(:test) do
gem 'webmock'
gem 'vcr'
end
group(:development, :test) do
gem 'awesome_print'
gem 'capybara'
gem 'database_cleaner'
gem 'dotenv-rails'
gem 'faker'
gem 'fuubar'
gem 'guard-rspec', require: false
gem 'phantomjs', require: 'phantomjs/poltergeist'
gem 'poltergeist'
gem 'pry-byebug'
gem 'pry-rails'
gem 'rack_session_access'
gem 'rspec-rails'
gem 'selenium-webdriver'
gem 'simplecov'
gem 'typhoeus'
end
group(:development) do
gem 'git-storyid'
gem 'html2fortitude'
gem 'letter_opener'
gem 'meta_request'
gem 'quiet_assets'
gem 'spring-commands-rspec'
gem 'spring'
gem 'web-console'
gem 'xray-rails'
end
…would be great! This isn't an extremely high-priority feature, but generators are one of the things that really make Rails development a joy.
@alexch and I discovered that the following code works as expected in fortitude 0.9.3 but fails in 0.9.4. Seems something gets confused when you pass f.label
both args and a block.
form_for(some_obj, url: some_path(some_obj)) { |f|
...
f.label(field_name, value: answer_key) { text answer_text }
Stacktrace:
ActionView::Template::Error:
wrong number of arguments (0 for 1+)
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/yielded_object_outputter.rb:8:in `block in wrap_block_as_needed'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:38:in `block in capture'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:200:in `with_output_buffer'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:38:in `capture'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/tags/label.rb:36:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/form_helper.rb:750:in `label'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/form_helper.rb:1585:in `label'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/yielded_object_outputter.rb:33:in `method_missing'
# ./app/views/histories/edit.html.rb:76:in `block (3 levels) in history_choice'
# (eval):32:in `tag_div'
# ./app/views/histories/edit.html.rb:75:in `block (2 levels) in history_choice'
# ./app/views/histories/edit.html.rb:68:in `each'
# ./app/views/histories/edit.html.rb:68:in `block in history_choice'
# (eval):12:in `tag_fieldset'
# ./app/views/histories/edit.html.rb:65:in `history_choice'
# ./app/views/histories/edit.html.rb:18:in `block (2 levels) in content'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/yielded_object_outputter.rb:10:in `call'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/yielded_object_outputter.rb:10:in `block in wrap_block_as_needed'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:38:in `block in capture'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:200:in `with_output_buffer'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:38:in `capture'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/form_helper.rb:434:in `form_for'
# (eval):3:in `form_for'
# ./app/views/histories/edit.html.rb:12:in `block in content'
# (eval):32:in `tag_div'
# ./app/views/histories/edit.html.rb:11:in `content'
# (eval):3:in `run_content'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:35:in `block in render_to'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:79:in `record_widget'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:33:in `render_to'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/renderer.rb:38:in `block (2 levels) in render'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:183:in `with_yield_block'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/renderer.rb:37:in `block in render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/helpers/capture_helper.rb:200:in `with_output_buffer'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/renderer.rb:28:in `render'
# ./app/views/histories/edit.html.rb:1:in `_app_views_histories_edit_html_rb__2472174839435550605_70144171257780'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/template.rb:145:in `block in render'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `block in instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/template.rb:339:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/template.rb:143:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/template_renderer.rb:55:in `block (2 levels) in render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/abstract_renderer.rb:38:in `block in instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `block in instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/abstract_renderer.rb:38:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/template_renderer.rb:54:in `block in render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/template_renderer.rb:62:in `render_with_layout'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/template_renderer.rb:53:in `render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/template_renderer.rb:17:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/renderer.rb:42:in `render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/renderer/renderer.rb:23:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/rendering.rb:99:in `_render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/streaming.rb:217:in `_render_template'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/rendering.rb:82:in `render_to_body'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/rendering.rb:32:in `render_to_body'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/renderers.rb:32:in `render_to_body'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/abstract_controller/rendering.rb:25:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/rendering.rb:16:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/core_ext/benchmark.rb:12:in `ms'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:44:in `block in render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:87:in `cleanup_view_runtime'
# ~/.rvm/gems/ruby-2.1.4/gems/activerecord-4.1.10/lib/active_record/railties/controller_runtime.rb:25:in `cleanup_view_runtime'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:43:in `render'
# ~/.rvm/gems/ruby-2.1.4/gems/fortitude-0.9.4/lib/fortitude/rails/rendering_methods.rb:85:in `render_with_fortitude'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/implicit_render.rb:10:in `default_render'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/implicit_render.rb:5:in `send_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/abstract_controller/base.rb:189:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/rendering.rb:10:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:113:in `call'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:113:in `call'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:552:in `block (2 levels) in compile'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:502:in `call'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:502:in `call'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/callbacks.rb:86:in `run_callbacks'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/abstract_controller/callbacks.rb:19:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/rescue.rb:29:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `block in instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/activesupport-4.1.10/lib/active_support/notifications.rb:159:in `instrument'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/activerecord-4.1.10/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/abstract_controller/base.rb:136:in `process'
# ~/.rvm/gems/ruby-2.1.4/gems/actionview-4.1.10/lib/action_view/rendering.rb:30:in `process'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/test_case.rb:595:in `process'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/test_case.rb:64:in `process'
# ~/.rvm/gems/ruby-2.1.4/gems/actionpack-4.1.10/lib/action_controller/test_case.rb:495:in `get'
# ./spec/controllers/histories_controller_spec.rb:18:in `block (3 levels) in <top (required)>'
Fortitude appears to be pretty well Rails 5 compatible, with the exception of the use of alias_method_chain
, which is deprecated and should be replaced with Module.prepend
. Currently, running fortitude on a Rails 5 app throws a bunch of ugly deprecation warnings on app startup:
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /Users/<app>/config/environment.rb:5)
It should be possible to do
form_for :test_form do |f|
f.text_field "hello"
f.fields_for :inner_thing do |inner|
inner.text_field "greets"
end
end
But fields_for
is not a helper defined on form_for
helper.
I added fields_for
to the output_yielded_methods
, which fixed it for my example above, generting the correct HTML:
<form accept-charset="UTF-8" action="/test_form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="j4Dax68aX/t7ajwBlpTTjeMT5MAaZjrNVYfE/yTW9ts=" /></div><input id="test_form_hello" name="test_form[hello]" size="30" type="text" /><input id="test_form_inner_thing_greets" name="test_form[inner_thing][greets]" size="30" type="text" /></form>
But, if I add an additional tag within the fields_for
block, inner.text_field "greets"
is no longer output.
form_for :test_form do |f|
f.text_field "hello"
f.fields_for :inner_thing do |inner|
inner.text_field "greets"
div "hello"
end
end
Outputs the HTML, (notice the div tag is there, but not the input)
<form accept-charset="UTF-8" action="/test_form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="j4Dax68aX/t7ajwBlpTTjeMT5MAaZjrNVYfE/yTW9ts=" /></div><input id="test_form_hello" name="test_form[hello]" size="30" type="text" /><div>hello</div></form>
After testing fortitude with Roda ( https://github.com/jeremyevans/roda ), fortitude blew up without explicit locals hash.
I have fixed this in roda (jeremyevans/roda#8 ), but @jeremyevans suggested to fix it also in fortitude.
My guess would be that line here:
widget_assigns = widget_assigns.merge(locals)
, would not work if locals are nil
Let's say I have a FullNavbar
widget, that needs to display one of multiple Menu::Whatever
widgets based on conditions determined outside itself that it shouldn't have any reason to be privy to. "Fine," I think, "I'll just assign a widget class to a menu_adder
needs
variable (change in strategy); the Navbar
will at some point have the line widget menu_adder
, and all will be fine and dandy. A five-minute job."
"A five-minute job" as in SS Minnow's "three-hour tour", apparently...
The error as reported by MiniTest::Spec running my specs, along with the first lines of stack dump down to my widget
code, are
Widgets::Page::FullNavbar::renders markup via the #to_html method that::by default::has a wrapper element::contains a Bootstrap container that::contains a "navbar-collapse" :div which::contains a "navbar-collapse" :div that::contains a :ul element that#test_0001_has the correct CSS classes:
RuntimeError: can't modify frozen #<Class:#<Class:0x007fe5363a77a8>>
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/needs.rb:60:in `needs_as_hash'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/needs.rb:127:in `rebuild_my_needs_methods!'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/needs.rb:116:in `block in ensure_needs_methods_are_valid!'
/path/to/the_app/vendor/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/notifications.rb:166:in `instrument'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/integration.rb:14:in `rebuilding'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/needs.rb:115:in `ensure_needs_methods_are_valid!'
(eval):2:in `assign_locals_from'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:85:in `initialize'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:58:in `new'
/path/to/the_app/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:58:in `widget'
/path/to/the_app/app/views/page/full_navbar.rb:57:in `block in navbar_menu'
The mentioned line 57 is the widget
call in
module Widgets
module Page
class FullNavbar < Views::Base
needs menu_adder
# ...
def navbar_menu
ul(class: 'nav navbar-nav') do
widget menu_adder
end # ul
end
end # class
end
end
Any ideas on how to go about tackling this sort of thing? Or should I go back to my original plan and pass in a lambda for menu_adder
rather than a widget?
When I have a widget that generates a raw-HTML form
tag (rather than using form_for
or similar helpers), I'm responsible for explicitly including CSRF-protection meta
tags as hidden fields. Fine; I'd think that should just be a matter of calling the :csrf_meta_tags
helper in the form (which Fortitude lists in Fortitude::Rails::Helpers
.
Simple, right? Not so much…
$ docker-compose run --rm app ruby -Itest test/views/form/base_test.rb --fail-fast
# Running tests with run options --fail-fast --seed 27516:
E
Error:
Widgets::Form::Base::has a #to_html method that::with the default control_group_content parameter::renders a containing :form tag with::the correct attributes for#test_0002_accept-charset:
NoMethodError: undefined method `csrf_meta_tags' for Fortitude::Rails::Helpers:Module
app/views/form/base.rb:33:in `csrf_protection_not_redundant'
app/views/form/base.rb:16:in `block in content'
app/views/form/base.rb:47:in `block in form_widget'
app/views/form/base.rb:47:in `form_widget'
app/views/form/base.rb:14:in `content'
test/views/form/base_test.rb:14:in `block (3 levels) in <main>'
test/views/form/base_test.rb:15:in `block (3 levels) in <main>'
test/views/form/base_test.rb:32:in `block (6 levels) in <main>'
Interrupted. Exiting...
Finished tests in 0.033643s, 29.7243 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
What am I missing?
Directly relevant widget source here; any of these tests will demonstrate the failure (as rendering the form to HTML will fail).
div nil, class: "hello"
Expected
<div class="hello"></div>
Got
<div></div>
Rails renders the csrf_meta_tags
helper as a text element seen here
Fortitude complains with an error
The widget #<_> tried to render an element that is not allowed by element nesting rules: you can't put a <_text> inside a <html>. (See 'http://www.w3.org/TR/html5/semantics.html#the-html-element' for more details.)
What is the status of this project? Is it still being worked on?
Is this gem still maintained? Is it planned to update it to support newer Rails?
I often get 'superclass mismatch' errors after modifying and reloading templates in development mode.
The file structure is:
app/views/foo/edit.html.rb
module Views
module Foo
class Edit < Views::Base
def content
widget(Views::Foo::Form, ...)
end
end
end
end
app/views/foo/form.rb
module Views
module Foo
class Form < Views::Base
def content
...
end
end
end
end
The error is:
ActionView::Template::Error (superclass mismatch for class Edit):
1: module Views
2: module Foo
3: class Edit < Views::Base
app/views/foo/edit.html.rb:3:in `<module:Foo>'
...
activesupport (4.1.6) lib/active_support/dependencies.rb:225:in `require_dependency'
.../.rvm/gems/ruby-2.1.2/bundler/gems/fortitude-11a268dda85d/lib/fortitude/rails/template_handler.rb:7:in `call'
...
The exact issue is the widget
line. Theoretically I should be able to refer to either Views::Foo:Form
, or just Form
since we're in the Views::Foo
namespace. And indeed, if I start the server with either of those, and don't touch that line, things work great. However, if I change from one format to the other, the error pops up. In fact, from then on, even if I change back to the original format, Rails keeps throwing the error when it tries to load the app/views/foo/edit.html.rb
file. It's as if loading the widget file a second time in a slightly different way causesViews::Base
to end up with two different definitions.
I can resolve the issue by adding require_dependency 'views/base'
at the top of the templates.
System info:
$ ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
$ rails -v
Rails 4.1.6
We consistently get errors when Rails tries to reload views in development mode. The files load correctly the first time, but throw an 'uninitialized constant' error the second time.
For example:
We have the following directory structure:
app/views/base.rb
module Views
class Base < Fortitude::Widget
doctype :html5
...
end
end
app/views/logged_out/index.html.rb
class Views::LoggedOut::Index < Views::Base
include Views::Shared::AuthPanel
def content
...
end
end
The exception we get is:
ActionView::Template::Error (uninitialized constant Views::LoggedOut::Index):
1: class Views::LoggedOut::Index < Views::Base
2: include Views::Shared::AuthPanel
3:
4: def content
app/views/logged_out/index.html.rb:1:in '_app_views_logged_out_index_html_rb__3228983590333935155_70328782437080'
If we rename the file to be app/views/logged_out/index.rb instead of .html.rb, the problem goes away. However, we need the .html so that Rails doesn't try to use the fortitude views to render json responses.
Getting following deprecation warning when using fortitude with Rails 6.0.0
DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must
now accept two parameters, the view object and the source for the view object.
Change:
>> #<Fortitude::Rails::TemplateHandler:0x000055c7f4ffcc58>.call(template, block)
To:
>> #<Fortitude::Rails::TemplateHandler:0x000055c7f4ffcc58>.call(template, block, source)
(called from <top (required)> at config/application.rb:7)
I'm trying to build the middleman documentation but retina_images is missing. I see the parcels repo on GitHub but not retina_images.
I'm getting explosions from the Fortitude railtie that's monkey-patching ActionView to help it autoload view classes. Looks like the monkey-patched method inside ActionView changed the method arity but Fortitude hasn't matched? I honestly don't really understand why my particular setup isn't working because I've used other Rails projects with higher and lower versions and didn't have problems.
I also hacked Fortitude gem source and added the missing method param, passing it straight through and got everything working properly.
I'm currently on Rails 4.2.6 and attempting to use Foritude 0.9.4.
Any advice would be appreciated!
ArgumentError:
wrong number of arguments (given 5, expected 4)
# /Users/glenn/.rvm/gems/ruby-2.3.1/gems/fortitude-0.9.4/lib/fortitude/rails/railtie.rb:251:in find_templates_with_fortitude' # /Users/glenn/.rvm/gems/ruby-2.3.1/gems/actionmailer-4.2.6/lib/action_mailer/base.rb:914:in
each_template'
# /Users/glenn/.rvm/gems/ruby-2.3.1/gems/actionmailer-4.2.6/lib/action_mailer/base.rb:900:in collect_responses' # /Users/glenn/.rvm/gems/ruby-2.3.1/gems/actionmailer-4.2.6/lib/action_mailer/base.rb:829:in
mail'
# ./app/mailers/application_mailer.rb:20:in mail_with_defaults' # ./app/mailers/welcome_mailer.rb:4:in
welcome_member'
delegate_object
you use for the rendering_context
is a controller instance instead of the view_context
, so view helpers are not available (and other weird stuff happens):widget
option, Erector tries to render the Fortitude widget somewhere deep within render_without_fortitude
view_context.assigns
for needs by default):text
option correctly, but my layout still renders empty. (I noticed if I disabled the layout then the content would come through)Lastly, I'm curious why you chose to do it the way you did, Erector does the following to register a :widget
renderer:
require 'action_controller/metal/renderers'
ActionController.add_renderer :widget do |widget, options|
# return result of render
end
I'm using a few custom defined view paths, without going into too much detail I need to look in various <path>/app/views
in addition to the standard app/views
path.
I have a works-for-me hacked-up version of this available here: bigfix@f8aa0ed
It looks at the Rails paths configuration variable for app/views
to pull a list of view paths to use, then loops over the old code to include files from all such locations.
(Largely a conceptual variation on #28)
Is it possible to test rendering of widgets from "fast Ruby" tests that don't load the entire Rails environment, or is (what I assume to be) the ActionView
dependency dependent on enough outside Rails "magic" to be pulled out by itself reasonably? Has anyone successfully accomplished this?
Erector lets you do something like this:
widget Views::Thing, hello: "world" do
div "hello world"
end
# or
widget Views::Thing.new(hello: "world") {
div "hello world"
}
# thing.rb
class Views::Thing < Erector::Widget
needs :hello
def content
div class: "hi" do
call_block
end
end
end
http://www.rubydoc.info/github/erector/erector/Erector/AbstractWidget#call_block-instance_method
Would be nice if fortitude supported it
in fortitude/lib/fortitude/rails/template_handler.rb
you have Rails.application.paths['app/views']
, which only searches path set via the configuration, and not ones added added at request time like those from prepend_view_path
view_paths
can be used to get all the paths: http://api.rubyonrails.org/classes/ActionView/ViewPaths/ClassMethods.html#method-i-view_paths
The only issue with this is that it must be called in a request context, so the TemplateHandler
's call method needs to be updated to do the look up at render time.
Howdy! I looked in the codebase and didn't see one, so apologies if it already exists, but is there a CLI to convert Fortitude files to HTML and vice-versa? Something like https://github.com/erector/erector/blob/master/lib/erector/erect/erect.rb#L118-L148 In the context of a Rails app in particular.
With Erector, as demonstrated in their specs, testing widgets using #to_html
, #to_a
, etc, was drop-dead simple. Writing simple tests like
it 'renders the expected content' do
expect(FooWidget.new.to_html).must_equal expected_content
end
would Just Work. Fortitude adds an internal, apparently-undocumented rendering context that leads the above MiniTest::Spec code to fail with the obviously-intended-to-be-helpful message
Fortitude::Errors::NoBlockToYieldTo: You're trying to call 'yield' (or 'yield_from_widget', or the Erector-compatibility method 'call_block')
from the widget #<Views::FooWidget:xxxxxxxx>; however, there is nothing to yield to. Fortitude
looks for something to yield to in this order:
1. A block passed to a yield at render time directly (usually via the 'widget' call);
2. A block passed to the constructor of the widget;
3. The layout the widget is being rendered in.
None of these exist here, and so calling 'yield', 'yield_from_widget', or 'call_block' is an
undefined operation.
So what should I be doing instead to unit-test a widget? Isn't the whole point of "Views Are Code" supposed to be that we can treat widgets and widget-derived code like pages the same as any other classes in our system — with testing, composition, SOLID, and so on? Of course feature specs work, but that's only half the job.
What has everybody else been doing?
or at least 0.9.5, see also #44 (comment)
Sorry, I think this was introduced during the fix of #3...
This line throws a 'No such file or directory' error when I try to render Widgets.
The file structure is:
app/views/foo/edit.html.rb
module Views
module Foo
class Edit < Views::Base
needs :bar
def content
widget(Form, bar: bar)
end
end
end
end
app/views/foo/form.rb
module Views
module Foo
class Form < Views::Base
needs :bar
def content
text bar.baz
end
end
end
end
The error is:
ActionView::Template::Error:
No such file or directory @ dir_initialize - .../app/views/foo/edit
# .../.rvm/gems/ruby-2.1.2/gems/fortitude-0.0.6/lib/fortitude/rails/railtie.rb:154:in `open'
# .../.rvm/gems/ruby-2.1.2/gems/fortitude-0.0.6/lib/fortitude/rails/railtie.rb:154:in `entries'
It looks like fortitude is interpreting some of the file name (edit) as part of the directory structure.
Kinda a weird use case, I'll admit, but as we're converting over our applications from Erector -> Fortitude, they still have dependencies that include Erector widgets. I thought it would be as easy as:
class FortitudeWidget < Views::Base
def content
rawtext ErectorWidget.new.to_html
end
end
But the problem is that the ErectorWidget
doesn't have access to the helpers
object, so if it tries to reference e.g. current_user
, it fails.
Any advice on how to pass in either parent
or helpers
? Here a link to some related lines in the Erector codebase.
In Erector, this works as expected:
class HomeController
def index
@project = Project.find(5)
end
end
class Views::Home::Index < Views::Base
def content
h1 @project.name
render 'components/project'
end
end
class Views::Components::Project < Views::Base
needs :project
def content
text @project.description
end
end
We don't need to explicitly pass @project
to the project
partial, since it has needs :project
declared.
However, in Fortitude, @project is nil
inside of the project_details
partial. Is this a bug, or am I doing something wrong?
Here's my config:
use_instance_variables_for_assigns true
format_output false
start_and_end_comments false
extra_assigns :use
See http://www.quirksmode.org/css/condcom.html
Erector supported this type of comment as a block comment.
Currently can workaround this like so:
rawtext '<!--[if lt IE 8]>'
# Some stuff
rawtext '<![endif]-->'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.