Skip to content

Commit b3fa656

Browse files
author
Nils Henning
committed
[TASK] update rails integration guide
1 parent d5d3bee commit b3fa656

File tree

1 file changed

+202
-10
lines changed

1 file changed

+202
-10
lines changed

docs/guides/300-rails_integration/README.md

Lines changed: 202 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ All this solutions are going to show you different approaches from which you can
77

88
In order to explain the following approaches we will shortly describe a scenario. Let's assume a very simple app, which has a landing page, products index page and a products show page. The landing page displays a nav, search bar and 3 product teasers. The products index page lists all components reusing the products teaser partial. The products show page just renders the details of a product.
99

10-
1. [Custom components](#custom-components)
11-
2. [In progress...](#in-progress)
1210

1311
## Custom components
1412

@@ -32,11 +30,12 @@ Start by creating a file called `teaser.rb` in `app/matestack/components/product
3230

3331
```ruby
3432
class Components::Products::Teaser < Matestack::Ui::Component
33+
include ::Rails.application.routes.url_helpers
3534

3635
requires :product
3736

3837
def response
39-
link path: product_path(product) do
38+
link path: product_path(product), class: 'product-teaser' do
4039
div do
4140
heading size: 2, text: product.name
4241
paragraph text: product.description
@@ -48,21 +47,21 @@ class Components::Products::Teaser < Matestack::Ui::Component
4847
end
4948
```
5049

51-
We inherit from `Matestack::Ui::Component` to create our teaser component. As it should display product informations it requires a product. We can access this product through a getter method `product`. We have now a teaser component, but in order to use it we have to register it and include our registration in our `ApplicationController`.
50+
We inherit from `Matestack::Ui::Component` to create our teaser component. As it should display product informations it requires a product. We can access this product through a getter method `product`. To access Rails url helpers we have to include `Rails.application.routes.url_helpers` as components usually get access to them through the pages but we render our component outside a matestack page. Now we have now a teaser component, but in order to use it we have to register it and include our registration in our `ApplicationController`.
5251

5352
Let's register our component by creating a component registry in `app/matestack/components/registry.rb`.
5453

5554
```ruby
5655
module Components::Registry
5756

58-
Matestack::Ui::Core::Component::Registry.register_component{
57+
Matestack::Ui::Core::Component::Registry.register_components(
5958
product_teaser: Components::Products::Teaser
60-
}
59+
)
6160

6261
end
6362
```
6463

65-
The last thing we have to do before we can use our component is to include our registry in the `ApplicationController`.
64+
The last things we have to do before we can use our component is to include our registry in the `ApplicationController`.
6665

6766
```ruby
6867
class ApplicationController < ActionController::Base
@@ -71,6 +70,16 @@ class ApplicationController < ActionController::Base
7170
end
7271
```
7372

73+
and make matestack `matestack_component` helper available in views by also including the `Matestack::Ui::Core::ApplicationHelper` in our `ApplicationHelper`.
74+
75+
`app/helpers/application_helper.rb`
76+
77+
```ruby
78+
module ApplicationHelper
79+
include Matestack::Ui::Core::ApplicationHelper
80+
end
81+
```
82+
7483
Now we can use our matestack component in our view. Replacing the `render partial:` call from before with a call to `matestack_component` on our landing page.
7584

7685
`app/views/static/index.html.erb`.
@@ -80,14 +89,197 @@ Now we can use our matestack component in our view. Replacing the `render partia
8089
<%= render partial: 'products/teaser', collection: @products, as: :product %>
8190

8291
<!-- using our component -->
83-
<%= @products.each do |product|>
84-
<%= matestack_component :product_teaser, product: product>
92+
<%= @products.each do |product| %>
93+
<%= matestack_component :product_teaser, product: product %>
8594
<% end %>
8695
```
8796

8897
This approach gives you access inside this component to all matestack features except page transitions. You can use `async`, `toggle`, `collection`, `actions`, `forms`, `isolated`, `onclick` and more vue.js components inside your components, enabling you to build modern and interactive UIs in pure ruby, while keeping a low effort for integrating or slowly migrating your project to matestack.
8998

99+
To use matestack page transition feature you have to use matestack pages inside a matestack app.
100+
101+
## Components reusing views or partials
102+
103+
Another method to integrate matestack in your rails application is by reusing your partials with components. Matestack `rails_view` component offers the posssibility to render a view or partial by passing it's name and required params to it. You can either replace your views step by step refactoring them with components which reuse partials and keep the migration of these partials for later or you can reuse a complete view and create a page with a single component rendering the view.
104+
105+
### Components reusing partials
106+
107+
Above we created a new matestack component, recreating our product teaser partial, but instead of doing so we could also reuse this partial with a component. Let's create a matestack page and app, which will list trending products. We add another route `get :trending, to: 'static#trending'` to our `config/routes.rb` file. We create a matestack app in `app/matestack/shop/app.rb`.
108+
109+
```ruby
110+
class Shop::App < Matestack::Ui::App
111+
112+
def response
113+
head_section
114+
yield_page
115+
end
116+
117+
private
118+
119+
def head_section
120+
header do
121+
div class="round-header-background"
122+
nav do
123+
div class="logo" { plain "RAILS" }
124+
end
125+
div class="hero search" do
126+
heading text: 'Shopping never was easier'
127+
end
128+
end
129+
end
130+
end
131+
```
132+
133+
It displays our header which we used on the other pages too and renders it as an app layout. Below the head section the page will be rendered, specified by the call to `yield_page`.
134+
135+
Now we create our trending page in `app/matestack/pages/trending.rb`.
136+
137+
```ruby
138+
class Shop::Pages::Trending < Matestack::Ui::Page
139+
140+
def response
141+
heading text: 'Trending products'
142+
main do
143+
@products.each do |product|
144+
rails_view partial: 'products/teaser', product: product
145+
end
146+
end
147+
end
148+
149+
end
150+
```
151+
152+
As you see we used the `rails_view` component here to render our products teaser partial. Given the string rails searches for a partial in `app/views/products/_teaser.html.erb`. As our product teaser partial uses a `product` we pass in a product. All params except those for controlling the rendering like `:partial` or `:view` get passed to the partial or view as locals. Therefore the partial teaser can access the product like it does.
153+
154+
To render our trending page within the shop app to see the `rails_view` component working we have to make sure our `app/layouts/application.html.erb` contains an html element with the id "matestack-ui".
155+
156+
```html
157+
<!DOCTYPE html>
158+
<html>
159+
<head>
160+
<title>RailsLegacy</title>
161+
<%= csrf_meta_tags %>
162+
<%= csp_meta_tag %>
163+
164+
<%= stylesheet_link_tag 'application', media: 'all' %>
165+
<%= javascript_pack_tag 'application' %>
166+
</head>
167+
168+
<body>
169+
<div id="matestack-ui">
170+
<%= yield %>
171+
</div>
172+
</body>
173+
</html>
174+
```
175+
176+
Lastly we implement the controller action in the `StaticController` which should render our page within our `Shop::App`. We could set the corresponding app by adding a call to `matestack_app Shop::App` at the top of our controller or by using `matestack_app: Shop::App` in our render call. In this example we use the second option.
177+
178+
```ruby
179+
class StaticController < ApplicationController
180+
181+
def index
182+
@products = Product.limit(3)
183+
end
184+
185+
def trending
186+
@products = Product.limit(3) # our trending products - for simplicity we just select the first three retrieved records
187+
render Shop::Pages::Trending, matestack_app: Shop::App
188+
end
189+
190+
end
191+
```
192+
193+
If we now start our rails server with `rails s` and visit [localhost:3000/trending](http://localhost:3000/trending) we can see our `rails_view` component renders our partial with the correct data.
194+
195+
`rails_view` works with ERB, Haml and Slim Templates. ERB and Haml are supported out of the box. In order to use slim templates the slim gem needs to be installed.
196+
197+
### Components reusing views
198+
199+
As mentioned above the `rails_view` component can not only render partials but also views. You can use this behavior to quickly switch to matestack pages and apps, allowing for page transitions between your views, which enables a more single page application or app like behaviour. Above we introduced our shop app, which we used to wrap our trending products page. We now want to be able to transition between the trending and startpage. Therefore our startpage has to be a matestack page and not a rails view. To simply achieve this we create another page in `app/matestack/shop/pages/` called `index.rb`.
200+
201+
```ruby
202+
class Shop::Pages::Index < Matestack::Ui::Page
203+
204+
def response
205+
rails_view view: 'static/index', products: products
206+
end
207+
208+
end
209+
```
210+
211+
As we moved the header inside the shop app (but without the form which we will just leave out for simplicity) and our products will not be accessible via instance variable `@products` but instead via the local `products` we need to make slight changes to our view. Removing the header and change all appearances of `@products` to `products`.
212+
213+
```html
214+
<main>
215+
<%= render partial: 'products/teaser', collection: products, as: :product %>
216+
<% products.each do |product| %>
217+
<%= matestack_component :product_teaser, product: product %>
218+
<% end %>
219+
</main>
220+
221+
<div>
222+
<%= link_to 'All products', products_path %>
223+
</div>
224+
```
225+
226+
After that we update our `StaticController` in order to render our new page.
227+
228+
`app/controllers/static_controller.rb`
229+
230+
```ruby
231+
class StaticController < ApplicationController
232+
matestack_app Shop::App
233+
234+
def index
235+
@products = Product.limit(3)
236+
render Shop::Pages::Index
237+
end
238+
239+
def trending
240+
@products = Product.limit(3)
241+
render Shop::Pages::Trending
242+
end
243+
244+
end
245+
```
246+
247+
We moved setting the corresponding app to the top of our controller by calling `matestack_app` instead of specifying it in every render call to keep things dry. We can now visit [localhost:3000](http://localhost:3000) to see our index page working, reusing our old view.
248+
249+
The next thing we can do is to add transition links to our app to transition between our index and trending page.
250+
251+
```ruby
252+
class Shop::App < Matestack::Ui::App
253+
254+
def response
255+
head_section
256+
yield_page
257+
end
258+
259+
private
260+
261+
def head_section
262+
header do
263+
div class: "round-header-background"
264+
nav do
265+
div(class: "logo"){ plain "RAILS" }
266+
div class: 'links' do
267+
transition path: root_path, text: 'Home'
268+
transition path: trending_path, text: 'Trending'
269+
end
270+
end
271+
div class: "hero search" do
272+
heading text: 'Shopping never was easier'
273+
end
274+
end
275+
end
276+
end
277+
```
278+
279+
When we now access [localhost:3000](http://localhost:3000) and click on the trending link and home link, we see how only the content is replaced as those links are now matestack transitions.
280+
281+
So with `rails_view` we can quickly integrate matestack with ease in an existing application and use matestacks transition feature for a more app or single page application like behaviour.
90282

91-
## In progress...
283+
## Custom haml components
92284

93285
![Coming Soon](../../images/coming_soon.png)

0 commit comments

Comments
 (0)