-
Notifications
You must be signed in to change notification settings - Fork 44
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
feat: add inertia_config
to enable controller-specific config
#121
base: master
Are you sure you want to change the base?
Conversation
With this alone, the same Rails app could serve different Inertia apps, setting a different version for each one in base controllers.
def saved_version | ||
InertiaRails.version.is_a?(Numeric) ? InertiaRails.version.to_f : InertiaRails.version | ||
def coerce_version(version) | ||
server_version.is_a?(Numeric) ? version.to_f : 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.
is that a typo?
server_version.is_a?(Numeric) ? version.to_f : version | |
version.is_a?(Numeric) ? version.to_f : 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.
No, that's the original logic.
default_render: false, | ||
|
||
# Let Rails decide which layout should be used based on the controller configuration. | ||
layout: true, |
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 believe that's a breaking change, since current default is nil
.
We can write about that in the changelog, or add a default to Renderer#layout
:
def layout
# we can also raise a warning here?
return true if configuration.layout.nil?
configuration.layout
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.
I made the original change in #86.
The controller method was returning true
if there global was nil
, so the behavior stays the same.
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.
Just tested, if someone sets nil
manually, this PR will brake their code (Rails renders page without layout):
InertiaRails.configure do |config|
config.layout = nil
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.
It's unlikely that users are doing that, given it's the default.
That behavior would also be consistent with using layout: false
.
If this is released in a major version, I'd say it's more intuitive if whatever the user configures is not overriden internally.
As an alternative, we can raise if the user sets it to nil
, since it's more likely a mistake.
Finally, I'd suggest removing layout
in the future, it makes more sense to customize using plain Rails in controllers instead, although I'm not proposing we do this now.
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.
yup, that's a great addition, and since README uses true
as a default, a note in the changelog should be enough, I guess 👍
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 don't feel strongly about it, we could be strict in backwards compatibility first, and remove it later, just mentioning that I don't think it's as useful a setting after #86.
Thanks for the review 😃
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've re-introduced the layout.nil? ? true : layout
check, in order to minimize friction when upgrading. Thanks!
@@ -1,3 +1,3 @@ | |||
<%= inertia_headers %> | |||
<%= local_assigns[:inertia_ssr_head] %> |
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 wrap this in inertia_headers
helper for backwards compatibility?
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.
Agreed 👍
I would add it with a warning that it will be removed.
These are not headers, it's html
for the head
, so the name is inaccurate.
In addition, it does not make sense to call this in the controller, as it wouldn't have been set yet.
Also, rename it to `inertia_ssr_head`, which is a better description.
inertia_config
to enable controller-specific config
Shared data is now frozen to prevent Also, match the method names for instance variables. Updated a test that used to call `inertia_share` inside a `before_action` as that seems like something a user should never do.
d52201a
to
39710b7
Compare
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.
@ElMassimo Excellent PR, very important to make easy to set up Inertia V2. This #131 task could be easily resolved if this PR is merged
@@ -54,63 +54,6 @@ | |||
it { is_expected.to eq props.merge({ errors: errors }) } | |||
end | |||
|
|||
context 'multithreaded inertia share' 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.
@ElMassimo just for curiosity, why do you remove this test? It was failing or because we do not have this problem anymore by default?
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.
It's not possible to have multi-threading issues anymore, as the objects that can be shared between threads are now frozen (not writable, and thus not susceptible to concurrent writes either).
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.
Thanks for the response!!
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.
Fwiw, i pulled the branch and added these tests back (just out of curiosity), and they do still pass.
These were made unnecessary by #111. At the time, I asked @PedroAugustoRamalhoDuarte to keep the specs so we weren't changing spec + implementation at the same time. I'm good with removing them now that we have evidence that refactor passed the original spec. (kind of like adding a new DB column, migrating data, then removing the old column once everything is verified working in production instead of just renaming the column in one shot)
def inertia_layout | ||
layout = ::InertiaRails.layout | ||
def inertia_shared_data | ||
initial_data = session[:inertia_errors].present? ? {errors: session[:inertia_errors]} : {} |
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 used to set inertia_share(errors: {})
to mimic Laravel plugin's default, with this change — I always overwrite inertia's errors with my empty hash.
Should we move this to the end of the chain?
def inertia_shared_data
self.class._inertia_shared_data.filter_map { |shared_data|
if shared_data.respond_to?(:call)
instance_exec(&shared_data)
else
shared_data
end
}.reduce({}, &:merge).tap do |data|
data[:errors] = session[:inertia_errors] if session[:inertia_errors].present?
end
end
before_action do | ||
@_inertia_shared_plain_data = @_inertia_shared_plain_data.merge(hash) if hash | ||
@_inertia_shared_blocks = @_inertia_shared_blocks + [block] if block_given? | ||
def inertia_share(**attrs, &block) |
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 is a breaking change, should we continue supporting hashes or at least throw a deprecation at first, wdyt?
inertia_share({foo: 'bar'}) # => throws error
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.
Addressed in #137
|
||
InertiaRails.version.is_a?(Numeric) ? inertia_version.to_f : inertia_version | ||
def server_version | ||
controller.send(:inertia_configuration).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.
Controller might be nil (i.e. in case of 404 error), I think this is a valid fix:
controller.send(:inertia_configuration).version | |
config = controller ? controller.send(:inertia_configuration) : ::InertiaRails.configuration | |
config.version |
Hey @ElMassimo thanks for this PR. I'm digging into it now (at long last)! Just as a heads up, I resolved a merge conflict in the README and committed it to your branch. Hope that's not stepping on your toes. |
Description 📖
This pull request is a complete refactor of the implementation in order to introduce controller-specific configuration.
inertia_config
A new way for controllers to override the global configuration, and provide dynamic values, such as:
Just like
inertia_share
, configuration is inheritable, and subclasses can override values.In addition, all configuration options can now be procs (before only
version
supported this).Performance 🚀
The implementation of
inertia_share
no longer relies onbefore_action
, improving performance when calculating shared data at runtime, and reducing object allocations.As an additional benefit, we no longer run this code unnecessarily for non-Inertia requests.
Notes ✏️
Each commit is a gradual refactoring, and can be read in isolation (and passes all tests). I'd still suggest using Squash and Merge.
We also
freeze
config and shared data to prevent any mutations, ensuring it's safe for multiple threads to access the configuration from the controller class.