-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Rethinking Shared Data #115
Comments
Ok, so here are a couple examples of failing tests: First, #117 demonstrates that The situation changes a bit with the refactor to instance variables in #116. You can still get leaky data, but it's more awkward to get there. Here's the commit with the failing test. Because of the refactor to Both of these are contrived examples that are "incorrect" uses of Inertia. But I think it's reasonable for a developer to expect to share data on a per-action basis, instead of per-controller. Especially since other Rails controller class methods like That said, I don't think we need to solve that in order to approve #111. It replaces global storage with the per-request storage of instance variables. That removes the necessity for a lot of current workarounds without changing the public API at all. As the PR notes, conditional sharing can be a future improvement. |
Here a couple (untested) sketches for API changes that could support conditional rendering. Essentially just passing options to the The first one requires a breaking change. Plain data props must be defined in a module InertiaRails
module Controller
extend ActiveSupport::Concern
module ClassMethods
def inertia_share(props: nil, **options, &block)
before_action(**options) do
@_inertia_shared_plain_data = @_inertia_shared_plain_data.merge(props) if props
@_inertia_shared_blocks = @_inertia_shared_blocks + [block] if block_given?
end
end
end
end
end
class SomeController < ApplicationController
before_action props: { first_name: 'Brian' }, only: [:show]
before_action only: [:show] do
{
last_name: 'Knoles'
}
end
end And here's one where we configure the
|
@bknoles Thanks for the time invested in this refactor.
|
Can be closed, right? (one off the list) |
Yes, closed by #111 |
I'm leaving this open because I'm still pondering how to do per-action conditional sharing. @ElMassimo is doing the following in #121 : class InertiaConditionalSharingController < ApplicationController
inertia_share normal_shared_prop: 1
inertia_share do
{conditionally_shared_show_prop: 1} if action_name == "show"
end
# rest of the controller
end which is a perfectly workable way to do it. I'd still love to have syntax similar to inertia_share {thing: 1}, only: [:show]
inertia_share only: [:index, :show] do
# stuff goes here
end The existing method signature complicates it a bit, and it's a nice to have additional feature that would be unique to the Rails adapter, so I haven't actually looked too far into it. Perhaps we could use an upcoming major release to change the rules on the method signature! |
I think the appeal of In that sense, supporting |
Interesting! The Rails pattern I'm thinking about is DRYing up a DB lookup: class ThingsController < ApplicationController
before_action :load_thing, except: [:new, :index, :create]
# ....
def load_thing
@thing = Thing.find(params[:id]
end
end And how I imagine this would look for InertiaRails would be: class ThingsController < ApplicationController
inertia_share except: [:new, :index, :create] do
{thing: Thing.find(params[:id])
end
end You can do the original Rails pattern already if you are using the inertia instance props. But I actually prefer to explicitly write out the It's probably worth nothing that InertiaRails defining shared data at the controller level is already a fairly significant deviation from the original Laravel adapter, which explicitly defines the data as being app-wide: I like that we have finer granularity (controller vs. app-wide) available; I would consider per-action granularity just another step further down this path, allowing a different stylistic choice for devs. That said, I can see your point about the potential confusion in an app that has |
As I think about it, perhaps we should have considered deviating further from the Laravel design; Rails and Laravel just kinda have different patterns as Rails focuses on the "controller" where Laravel focuses on the A question I'm asking myself: If I could go back, would it have been cleaner to make |
inertia_rails |
Hmm, what might that look like? class ThingsController < ApplicationController
before_action :load_thing, except: [:new, :index, :create]
# ....
def load_thing
inertia_share thing: Thing.find(params[:id])
end
end It's a bit verbose for my taste. And to be honest, I can't quite see why it's better, but maybe I'm missing something? |
I think what @bknoles means is a version of inertia-rails that never touches any global state or uses any class methods (except for global configuration) and all state and methods live on the controller instance. It's better in the sense that questions about data leaking across requests don't even come up when everything is instance-bound from the beginning. |
I see. Thread-safety is indeed tricky, but there are many ways to achieve it (and even more ways to get it wrong 😅). Our current approach (thanks to @ElMassimo and @PedroAugustoRamalhoDuarte) using immutable objects in class-level variables is one way. Keeping everything on the controller instance is another valid approach. Since our implementation is already thread-safe, perhaps we could focus on the interface? That's what I'm aiming for here. So, does #137 address all the requirements from this issue? Or are there still some points we need to tackle? cc @bknoles |
Yea @buhrmi is right on here. It would have been a "safer" design choice to avoid class variables altogether. And now I've proposed a before-action-like API. In retrospect, making But our current |
#137 resolved this! |
Continuing the conversation from #108
A quick summary:
before_action
callbacks, called byinertia_share
.The text was updated successfully, but these errors were encountered: