-
Notifications
You must be signed in to change notification settings - Fork 21.5k
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
Introduce a context for rendering fixtures ERB. #13022
Conversation
Could this break applications that rely on the fact that currently methods are leaked? |
It depends on how you define "break". This only impacts fixture code, so it won't break the folks who don't have tests at all. Assuming you have tests, and you run them when you upgrade Rails, this will turn flaky tests into definite failures. I think the fixtures load order is currently decided by this call to For some restricted definition of "break", this is a breaking change. I am willing to write the documentation needed for devs who run into this to understand what's happening. At the same time, I consider that the change turns ticking bombs into problems that are immediately visible. For context, imagine this exploding all of a sudden in a continuous integration / continuous deployment environment. 💣 😢 |
of course by breaking I meant the tests and not production code. I don't see a reasonable way to issue depreciation warnings only in these cases so we need to compensate with docs. /cc @rafaelfranca |
@senny I figured you already knew the answer, and were asking for documentation purposes, or to have the answer spelled out in the PR log. Sorry, I misunderstood and my answer was weird :/ I didn't see a |
@pwnall sorry for being vague. It's good to reflect these thoughts in the PR so we can later link to it. I'll prepare the release notes and the upgrading guide today. I'll let you know when things are ready. |
@senny I added a Changelog entry and a paragraph in the fixtures documentation. Can I do anything else to help document this? |
You can add a section to the upgrading ruby on rails guide I pushed a first draft of the 4.1 release notes. You can add an entry in the notable changes section and even link to the upgrading guide. |
main object, and potentially leading to unexpected dependencies between | ||
tests. Now each fixture is evaluated in the context of unique | ||
`ActiveRecord::FixtureSet::RenderContext` subclass, so method definitions | ||
are not shared between fixtures. Helper methods inteded to be used by |
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.
typo inteded
=> intended
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.
Fixed.
@senny Thank you! I added notes in the upgrade guide and 4.1 release notes. I look forward to your feedback! |
`ActiveRecord::FixtureSet::RenderContext` subclass, so method definitions | ||
are not shared between fixtures. Helper methods intended to be used by | ||
multiple fixtures can be defined on | ||
`ActiveRecord::FixtureSet::RenderContext`, in `test_helper.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.
Let's use the short version from the release notes here as well. If people want to find out more then RenderContext
and the upgrade guide is the place to look:
- The ERB in fixture files is no longer evaluated in the context of the main object. Helper methods used by multiple fixtures should be defined on the
ActiveRecord::FixtureSet::RenderContext
class.
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.
Done. Thank you!
I added some minor comments. This is looking good. |
# A new subclass of this class is created each time the ERB renderer is | ||
# called so that methods defined in ERB templates do not leak into other | ||
# templates' context. | ||
class ActiveRecord::FixtureSet::RenderContext |
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 construction is very confusing. It only work because users will reopen a framework class to inject behavior. Could not we simplify this and make users create their own context and configure the fixture to use it? Or even better we can expose the context class and let people inject their own modules there. Something like:
Fixtures.context.include MyHelpers
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.
@rafaelfranca You can currently do
ActiveRecord::FixtureSet::RenderContext.include MyHelpers
I think we can get to where you want by
class ActiveRecord::FixtureSet
def self.context
ActiveRecord::FixtureSet::RenderContext
end
end
If I read this right, Fixtures is deprecated, so what you wrote would work and output a deprecation warning. The line below is slightly longer, but would work as is.
FixtureSet.context.include MyHelpers
What do you think?
I discussed this change with @rafaelfranca. We came to the conclusion that we should:
class Fixture
def self.context
@context ||= Class.new do
def get_binding
binding()
end
end
end
end
|
👍 |
This doesn't quite work :( I tried adding this to class ActiveRecord::FixtureSet
def self.context
@context ||= Class.new do
def get_binding
binding()
end
end
end
end One problem is that The other problem is that unless I define Thoughts? |
We can define |
About the |
@rafaelfranca In the end, we'll have a namespace where we have to pay a lot of attention when we add new names. I think that @senny I think that is correct. I also think it has to be defined in a "clean" namespace, because that namespace will be in lookup scope. |
I'm fine with a clean namespace but I don't want to see that module hack. It is ugly and hard to understand. So if there is a way to make a clean namespace without it 👍 |
@rafaelfranca What do you think about this version?
|
Very good ❤️ |
@rafaelfranca The other alternative I have is along the lines of ActiveRecord::FixtureSet::File.define_singleton_method(:render_context) do
Class.new ActiveRecord::FixtureSet.context do
def get_binding
binding()
end
end
end |
# Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path))) | ||
# end | ||
# end | ||
# ActiveRecord::FixtureSet.context.include FixtureFileHelpers |
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.
We will have to use send
here since include
is not public on Ruby 2.0
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.
Good point! Thank you!
@rafaelfranca Thank you! I'll go through the docs and update everything. |
@rafaelfranca I updated the docs and commit message. |
Fixture files are passed through an ERB renderer before being read as YAML. The rendering is currently done in the context of the main object, so method definitons leak into other fixtures, and there is no clean place to define fixture helpers. After this commit, the ERB renderer will use a new subclass of ActiveRecord::FixtureSet.context_class each time a fixture is rendered.
@senny Sorry, and thank you for catching that! I used |
@pwnall 👍 I think we are ready to go. Thank you very much for all the experimentation and updates, the speedy replies and the contribution. ❤️ |
Introduce a context for rendering fixtures ERB.
@senny Thank you and @rafaelfranca for the patience and guidance! |
Great we could make this in time to 4.1, thank you so much for the work |
I ran into this issue while trying to use binary data in my fixtures. The following guides motivated me to write this patch.
http://realityforge.org/code/rails/2006/04/06/loading-binary-data-into-rails-fixtures.html
http://www.tamingthemindmonkey.com/2011/08/18/rails-binary-data-in-fixtures
These define a new method right in the fixture file. I'm sure other people do this every once in a while too. With the current code, method definitions leak to other fixtures via the main object. This introduces subtle test inder-dependencies. Methods won't leak after this patch. (proven by new test case)
http://stackoverflow.com/questions/12644057/how-to-use-binary-data-in-rails-fixtures
This is a nice approach that's amenable to being packaged into a gem, except there is no clean place for adding this sort of functionality.
I look forward to your feedback.