Skip to content

Commit d395eb3

Browse files
Merge branch 'master' into fix-workflows
2 parents 4b0e8ec + 0d3bc00 commit d395eb3

37 files changed

+876
-42
lines changed

Appraisals

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
appraise "rails-7.0" do
2+
gem "rails", "~> 7.0"
3+
end
4+
15
appraise "rails-6.1" do
26
gem "rails", "~> 6.1.0"
37
end
@@ -13,7 +17,3 @@ end
1317
appraise "rails-5.1" do
1418
gem "rails", "~> 5.1.7"
1519
end
16-
17-
appraise "rails-5.0" do
18-
gem "rails", "~> 5.0.7", '>= 5.0.7.2'
19-
end

CHANGELOG.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,53 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.1.3] - 2023-11-03
8+
9+
* Depend on railties instead of rails so that applications which only use pieces of Rails can avoid a full Rails installation. Thanks @BenMorganMY!
10+
11+
## [3.1.2] - 2023-09-26
12+
13+
* Fix `have_exact_props` RSpec matcher in the situation where shared props are defined in a lambda that outputs a hash with symbolized keys
14+
15+
## [3.1.1] - 2023-08-21
16+
17+
* Fix broken partial reloads caused by comparing a list of symbolized keys with string keys from HashWithIndifferentAccess
18+
19+
## [3.1.0] - 2023-08-21
20+
21+
### Features
22+
23+
* CSRF protection works without additional configuration now.
24+
* Optional deep merging of shared props.
25+
26+
### Fixes
27+
28+
* Document Inertia headers. @buhrmi
29+
* Documentation typo fix. @lujanfernaud
30+
* Changelog URI fix. @PedroAugustoRamalhoDuarte
31+
32+
## [3.0.0] - 2022-09-22
33+
34+
* Allow rails layout to set inertia layout. Thanks @ElMassimo!
35+
* Add the ability to set inertia props and components via rails conventions (see readme)
36+
37+
## [2.0.1] - 2022-07-12
38+
39+
* Fix for a middleware issue where global state could be polluted if an exception occurs in a request. Thanks @ElMassimo!
40+
41+
## [2.0.0] - 2022-06-20
42+
43+
* Fix an issue with Rails 7.0. Thanks @0xDing and @aviemet!
44+
* Drop support for Rails 5.0 (and mentally, though not literally drop support for Rails < 6)
45+
46+
## [1.12.1] - 2022-05-09
47+
48+
* Allow inertia to take over after initial pageload when using ssr. Thanks @99monkey!
49+
50+
## [1.12.0] - 2022-05-04
51+
52+
* SSR!
53+
754
## [1.11.1] - 2021-06-27
855

956
* Fixed thread safety in the middleware. Thanks @caifara!

README.md

Lines changed: 262 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,268 @@
33

44
# Inertia.js Rails Adapter
55

6-
Visit [inertiajs.com](https://inertiajs.com/) for installation instructions, documentation, and to learn more.
6+
## Installation
7+
8+
### Backend
9+
10+
Just add the inertia rails gem to your Gemfile
11+
```ruby
12+
gem 'inertia_rails'
13+
```
14+
15+
### Frontend
16+
17+
Rails 7 specific frontend docs coming soon. For now, check out the official Inertia docs at https://inertiajs.com/ or see an example using React/Vite [here](https://github.com/BrandonShar/inertia-rails-template)
18+
19+
## Usage
20+
21+
### Responses
22+
23+
Render Inertia responses is simple, just use the inertia renderer in your controller methods. The renderer accepts two arguments, the first is the name of the component you want to render from within your pages directory (without extension). The second argument is an options hash where you can provide `props` to your components. This options hash also allows you to pass `view_data` to your layout, but this is much less common.
24+
25+
```ruby
26+
def index
27+
render inertia: 'Event/Index', props: {
28+
events: Event.all,
29+
}
30+
end
31+
```
32+
33+
#### Rails Component and Instance Props
34+
35+
Starting in version 3.0, Inertia Rails allows you to provide your component name and props via common rails conventions.
36+
37+
```ruby
38+
class EventsController < ApplicationController
39+
use_inertia_instance_props
40+
41+
def index
42+
@events = Event.all
43+
end
44+
45+
end
46+
```
47+
48+
is the same as
49+
50+
51+
```ruby
52+
class EventsController < ApplicationController
53+
def index
54+
render inertia: 'events/index', props: {
55+
events: Event.all
56+
}
57+
end
58+
end
59+
```
60+
61+
#### Instance Props and Default Render Notes
62+
63+
In order to use instance props, you must call `use_inertia_instance_props` on the controller (or a base controller it inherits from). If any props are provided manually, instance props
64+
are automatically disabled for that response. Instance props are only included if they are defined after the before filter is set from `use_inertia_instance_props`.
65+
66+
Automatic component name is also opt in, you must set the `default_render` config value to `true`. Otherwise, you can simply `render inertia: true` for the same behavior explicitly.
67+
68+
### Layout
69+
70+
Inertia layouts use the rails layout convention and can be set or changed in the same way. The original `layout` config option is still functional, but will likely be deprecated in the future in favor
71+
of using rails layouts.
72+
73+
```ruby
74+
class EventsController < ApplicationController
75+
layout 'inertia_application'
76+
end
77+
```
78+
79+
80+
### Shared Data
81+
82+
If you have data that you want to be provided as a prop to every component (a common use-case is information about the authenticated user) you can use the `shared_data` controller method.
83+
84+
```ruby
85+
class EventsController < ApplicationController
86+
# share syncronously
87+
inertia_share app_name: env['app.name']
88+
89+
# share lazily, evaluated at render time
90+
inertia_share do
91+
if logged_in?
92+
{
93+
user: logged_in_user,
94+
}
95+
end
96+
end
97+
98+
# share lazily alternate syntax
99+
inertia_share user_count: lambda { User.count }
100+
101+
end
102+
```
103+
104+
#### Deep Merging Shared Data
105+
106+
By default, Inertia will shallow merge data defined in an action with the shared data. You might want a deep merge. Imagine using shared data to represent defaults you'll override sometimes.
107+
108+
```ruby
109+
class ApplicationController
110+
inertia_share do
111+
{ basketball_data: { points: 50, rebounds: 100 } }
112+
end
113+
end
114+
```
115+
116+
Let's say we want a particular action to change only part of that data structure. The renderer accepts a `deep_merge` option:
117+
118+
```ruby
119+
class CrazyScorersController < ApplicationController
120+
def index
121+
render inertia: 'CrazyScorersComponent',
122+
props: { basketball_data: { points: 100 } },
123+
deep_merge: true
124+
end
125+
end
126+
127+
# The renderer will send this to the frontend:
128+
{
129+
basketball_data: {
130+
points: 100,
131+
rebounds: 100,
132+
}
133+
}
134+
```
135+
136+
Deep merging can be set as the project wide default via the InertiaRails configuration:
137+
138+
```ruby
139+
# config/initializers/some_initializer.rb
140+
InertiaRails.configure do |config|
141+
config.deep_merge_shared_data = true
142+
end
143+
144+
```
145+
146+
If deep merging is enabled by default, it's possible to opt out within the action:
147+
148+
```ruby
149+
class CrazyScorersController < ApplicationController
150+
inertia_share do
151+
{
152+
basketball_data: {
153+
points: 50,
154+
rebounds: 10,
155+
}
156+
}
157+
end
158+
159+
def index
160+
render inertia: 'CrazyScorersComponent',
161+
props: { basketball_data: { points: 100 } },
162+
deep_merge: false
163+
end
164+
end
165+
166+
# Even if deep merging is set by default, since the renderer has `deep_merge: false`, it will send a shallow merge to the frontend:
167+
{
168+
basketball_data: {
169+
points: 100,
170+
}
171+
}
172+
```
173+
174+
### Lazy Props
175+
176+
On the front end, Inertia supports the concept of "partial reloads" where only the props requested are returned by the server. Sometimes, you may want to use this flow to avoid processing a particularly slow prop on the intial load. In this case, you can use Lazy props. Lazy props aren't evaluated unless they're specifically requested by name in a partial reload.
177+
178+
```ruby
179+
inertia_share some_data: InertiaRails.lazy(lambda { some_very_slow_method })
180+
```
181+
182+
### Routing
183+
184+
If you don't need a controller to handle a static component, you can route directly to a component with the inertia route helper
185+
186+
```ruby
187+
inertia 'about' => 'AboutComponent'
188+
```
189+
190+
### SSR
191+
192+
Enable SSR via the config settings for `ssr_enabled` and `ssr_url`.
193+
194+
When using SSR, don't forget to add `<%= inertia_headers %>` to the `<head>` of your `application.html.erb`.
195+
196+
## Configuration
197+
198+
Inertia Rails has a few different configuration options that can be set anywhere, but the most common location is from within an initializer.
199+
200+
The default config is shown below
201+
```ruby
202+
InertiaRails.configure do |config|
203+
204+
# set the current version for automatic asset refreshing. A string value should be used if any.
205+
config.version = nil
206+
# enable default inertia rendering (warning! this will override rails default rendering behavior)
207+
config.default_render = true
208+
209+
# ssr specific options
210+
config.ssr_enabled = false
211+
config.ssr_url = 'http://localhost:13714'
212+
213+
config.deep_merge_shared_data = false
214+
215+
end
216+
```
217+
218+
## Testing
219+
220+
If you're using Rspec, Inertia Rails comes with some nice test helpers to make things simple.
221+
222+
To use these helpers, just add the following require statement to your `spec/rails_helper.rb`
223+
224+
```ruby
225+
require 'inertia_rails/rspec'
226+
```
227+
228+
And in any test you want to use the inertia helpers, add the inertia flag to the describe block
229+
230+
```ruby
231+
RSpec.describe EventController, type: :request do
232+
describe '#index', inertia: true do
233+
# ...
234+
end
235+
end
236+
```
237+
238+
### Assertions
239+
240+
```ruby
241+
RSpec.describe EventController, type: :request do
242+
describe '#index', inertia: true do
243+
244+
# check the component
245+
expect_inertia.to render_component 'Event/Index'
246+
247+
# access the component name
248+
expect(inertia.component).to eq 'TestComponent'
249+
250+
# props (including shared props)
251+
expect_inertia.to have_exact_props({name: 'Brandon', sport: 'hockey'})
252+
expect_inertia.to include_props({sport: 'hockey'})
253+
254+
# access props
255+
expect(inertia.props[:name]).to eq 'Brandon'
256+
257+
# view data
258+
expect_inertia.to have_exact_view_data({name: 'Brian', sport: 'basketball'})
259+
expect_inertia.to include_view_data({sport: 'basketball'})
260+
261+
# access view data
262+
expect(inertia.view_data[:name]).to eq 'Brian'
263+
264+
end
265+
end
266+
267+
```
7268

8269
*Maintained and sponsored by the team at [bellaWatt](https://bellawatt.com/)*
9270

gemfiles/rails_5.0.gemfile renamed to gemfiles/rails_7.0.gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
source "https://rubygems.org"
44

5-
gem "rails", "~> 5.0.7", ">= 5.0.7.2"
5+
gem "rails", "~> 7.0"
66

77
gemspec path: "../"

inertia_rails.gemspec

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
1414

1515
spec.metadata["homepage_uri"] = spec.homepage
1616
spec.metadata["source_code_uri"] = spec.homepage
17-
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
17+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
1818

1919
# Specify which files should be added to the gem when it is released.
2020
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
2525
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
2626
spec.require_paths = ["lib"]
2727

28-
spec.add_runtime_dependency "rails", '>= 5'
28+
spec.add_runtime_dependency "railties", '>= 5'
2929

3030
spec.add_development_dependency "bundler", "~> 2.0"
3131
spec.add_development_dependency "rake", "~> 13.0"
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
3434
spec.add_development_dependency "sqlite3"
3535
spec.add_development_dependency "appraisal"
3636
spec.add_development_dependency "responders"
37+
spec.add_development_dependency "debug"
3738
end
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
import { App } from '@inertiajs/inertia-react';
22
import React from 'react';
33
import { render } from 'react-dom';
4-
import axios from 'axios';
54
import { InertiaProgress } from '@inertiajs/progress';
65

76
document.addEventListener('DOMContentLoaded', () => {
87
InertiaProgress.init();
98
const el = document.getElementById('app')
109

11-
const csrfToken = document.querySelector('meta[name=csrf-token]').content;
12-
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken;
13-
1410
render(
1511
<App
1612
initialPage={JSON.parse(el.dataset.page)}
1713
resolveComponent={name => require(`../Pages/${name}`).default}
1814
/>,
1915
el
2016
)
21-
});
17+
});

0 commit comments

Comments
 (0)