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
Split out AV from AP, part 2 (WIP) #11396
Conversation
| @@ -10,12 +10,11 @@ module AbstractController | |||
| autoload :Base | |||
| autoload :Callbacks | |||
| autoload :Collector | |||
| autoload :DoubleRenderError, "abstract_controller/rendering.rb" | |||
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.
No need for .rb extension.
|
Thanks @josevalim for the review! I've fixed the small things. I was aware of moving both The main purpose of posting this was get opinion on the solution I finally stick to (https://github.com/strzalek/rails/blob/fc89313fe3f9e508dbe84616fa9a91db123337b0/actionpack/lib/action_controller/base.rb#L164-168) from others so please that into account that there's a lot rough edges to polish. |
| @@ -160,7 +161,11 @@ module ActionController | |||
| # render action: "overthere" # won't be called if monkeys is nil | |||
| # end | |||
| # | |||
| class Base < Metal | |||
| metal = Class.new(Metal) do | |||
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.
Does this have to be an anonymous class? Would it be easier to debug/extend if it was more explicit?
class MetalWithRendering < Metal
include AbstractController::Rendering
end
class Base < MetalWithRendering(MetalWithRendering may be a poor name, better ideas welcome)
I would also put some of the explanation in your PR as for the purpose of this class and the way its defined, as code comments describing this class, so people know why this "hack" is needed and why you don't just include Rendering into Base.
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.
I wouldn't make it a named class for now but we can always change it later. Also, you need to add code comments on why we need this class and you need to move the comments already existing to the top of class Base < metal otherwise the documentation will disappear.
|
@robin850 your comments have been addressed in the latest commit. It's true that it's WIP but it's also very helpful to have those kind of suggestions early in the process. Thank you! |
|
@strzalek : Thanks! I'm always interested in this kind of PR. Glad to help! |
| initializer "action_view.setup_action_pack" do |app| | ||
| ActiveSupport.on_load(:action_controller) do | ||
| ActionController::Base.send(:include, ActionView::Layouts) | ||
| end |
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.
You're supposedly already in AC::Base scope under the on_load block, so calling include directly should work I imagine (plus it'd work with rails-api that way).
|
Few weeks later and it looks like the whole thing is finished! Tests passes and sample application which doesn't use AV at all can be crated without any problem. You can find it here: https://github.com/strzalek/rails-sandbox Could you guys give it a look and review all this stuff? It would be very appreciated! /cc @drogus @josevalim @jeremy |
|
I will review the entire PR in the evening, but I just wanted to confirm that I've been able to build simple rails app, which just rendered JSON without AV. The simplest way to do that is to create app with |
|
Right, just like here: https://github.com/strzalek/rails-sandbox/blob/master/app/controllers/pages_controller.rb#L3 |
|
@strzalek I'm curious, what's the current status of AV? Is possible to use it without depend on AP? |
| @@ -12,17 +45,17 @@ def process_action(*) #:nodoc: | |||
|
|
|||
| # Check for double render errors and set the content_type after rendering. | |||
| def render(*args) #:nodoc: | |||
| raise ::AbstractController::DoubleRenderError if response_body | |||
| raise ::AbstractController::DoubleRenderError if self.response_body | |||
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.
What's the need to prefix with self here?
|
Hah, yes! Using this branch - YES. The You can clone it and give it a try |
|
AV's gemspec does not depend on AP in production, so the short answer is yes. However, it still has development dependency on AP, which I'm not sure is a good thing - it makes it harder to verify with tests that AV is actually truly independent of AP. |
|
@egilburg it might be possible to remove dev dep from AP on AV but well, I don't think it makes any sense. At the end of the day, AP and AV are still closely tight together and 95% of the project or maybe even more will be always using rails with AV. However, almost all of the tests concerning ActionView were moved away from AP to AV, and you can find them as integration ones in Besides that, in That's how it is now. I think that AV should stay as dev dep on AP for now. We have quite good coverage to be sure if stuff with/without AV works properly. Maybe it'll change some time in the future, during the process of refactoring tests, because I must admit, in some places you can find huge mess in there. Hope that explains everything, @egilburg. Let me know if you still have any questions. |
|
@strzalek I was talking about the other use case, using ActionView without Rails, something like this: https://gist.github.com/drogus/2472931 I'll try it to check if everything works as expected |
|
@guilleiguaran this is also possible, see the previous PR #11032 :) @strzalek also confirmed that it works with my gists when you change the Gemfile to include actionview instead of entire actionpack. |
|
Yeah, just like @drogus said, it was possible after previous PR :) |
|
I give a thought about AP and AV as dev dependency and actually it can - and maybe even should - be dropped. I've just pushed 2 commits, they're moving tests from At this state, only few small things are keeping AV as dep. I'll try to remove them tomorrow. |
HTML Scanner is part of ActionView and it should be loaded along with it
[ci skip]
The ones that were actually testing AV functionality and should belong in there
We're not dealing with templates here [ci skip]
Make it oneliner
|
Nice tool. I've updated gist with results: https://gist.github.com/strzalek/6293709 I'm again surprised in a good way What do you think |
| @@ -20,6 +20,7 @@ Gem::Specification.new do |s| | |||
| s.requirements << 'none' | |||
|
|
|||
| s.add_dependency 'actionpack', version | |||
| s.add_development_dependency 'actionview', version | |||
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.
Have you checked if action mailer actually works without action view? I guess I kind of ignored it when I was doing testing - if it's really as easy to use it without AV as actionpack it's ok to leave this line, otherwise we should either fix it or use add_dependency
|
I gave it another look and apart from one comment about action mailer it looks good to merge. I will be |
|
Great catch. That's true, it won't work without ActionView yet. I've pushed commit to make it first class dependency and I think we can merge it. However I think it'll be easy possible to make ActionMailer work without ActionView to make able sending simple emails, which don't require template rendering (http://guides.rubyonrails.org/action_mailer_basics.html#sending-emails-without-template-rendering), without the need of AV. I'll work on this later and send another PR not to hold this one. |
Remove dependency on Action View from Action Pack This set of changes removes the need of using Action View with Action Pack. Now you may use controllers without Action View, by rendering `:text` response or alternatively you can plug in your own rendering logic. This is especially handy when you're just dealing with APIs and don't need to include entire Action View just to render simple JSON responses.
|
|
|
|
|
For the record. This was quite big change, moving mostly core parts framework which means some issues may arise later on. Feel free to @mention me on github/twitter or mail me directly if there will be any problem caused by this change. |
|
|
|
@strzalek great work |
|
Awesome I do think that it would be great if development dependencies could be removed between AP and AV. Otherwise, it's easy for someone in a later patch to re-introduce coupling between the two, and the build won't notice. |
|
|
|
@egilburg like I've said in previous comments. The goal is get rid of dev-dependencies in the future and I will work on that later. Regarding re-introducing coupling, I think that test added in railties is quite good protection from that. |
| end | ||
|
|
||
| # Overwrite render_to_string because body can now be set to a rack body. | ||
| def render_to_string(*) | ||
| if self.response_body = super | ||
| string = "" | ||
| response_body.each { |r| string << r } | ||
| self.response_body.each { |r| string << r } | ||
| string |
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.
This method shouldn't set response_body, I saw it is "reverting" to nil in an ensure block but same could be accomplished with https://gist.github.com/spastorino/19079770e255adc97027.
Even more, shouldn't super already return a string instead of something that returns an object which responds to each?. In that case all the code in this method is useless.
/cc @josevalim @strzalek
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.
Yeah, well to be honest I have no idea what this code does. I've found this commit by @josevalim which introduced it: lukaszx0@4f04452
For me, it also looks like it could've be removed.
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.
Previously, response_body= had a bunch of complicated rules to set the body. So in order to reuse the logic, we assigned the value to response_body which normalized everything to an array. That's probably not the case today and I agree it can be refactored.
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.
Cool. I'll review this then
Hey,
This PR is a continuation of #11032.
I've moved all the rendering-related code to
ActionViewand added to itsrailtiescode that hooks all necessary things toActionPackif the AV is loaded.As straight forward as it sounds, it turned out it's not that easy. In the AP, all its components needs to be loaded in order. This introduced huge complication with loading AV stuff in railties as it was included at the end and needed to be included somewhere in the middle.
After discussing this issue with @drogus and @josevalim we agreed on simple solution - https://github.com/strzalek/rails/blob/fc89313fe3f9e508dbe84616fa9a91db123337b0/actionpack/lib/action_controller/base.rb#L164-168
With this code, we're now able to load
AV::RenderingbetweenAbstractController::RenderingandActionPack::Renderingsimply by:This PR is subject to discussion and WIP, not final solution.
What are your thoughts? Maybe you have other ideas how to abstract
ActionView?TODOS:
--skip_action_viewBasicRenderingimplementing onlyrender text:rendering_formatin controller/cc @drogus @josevalim @jeremy @wycats @spastorino @tenderlove