Hiya everybody!
The RubyMine group is consistently striving to supply help for brand new applied sciences for Ruby and Rails. Probably the most thrilling current additions to Rails is undoubtedly Hotwire, so we’ve ready an summary of this suite of frameworks and a tutorial on use an important Turbo and Stimulus options in your Rails app with RubyMine. This publish covers Stimulus; For Turbo, please see our earlier weblog publish.
Hotwire and Stimulus
What’s Hotwire?
Hotwire simplifies internet growth by sending HTML over the wire as a substitute of JSON (therefore the identify, which stands for “HTML over the wire”). This reduces the quantity of JavaScript builders want to jot down and the appliance must ship to the browser, whereas additionally conserving template rendering on the server. Hotwire is made up of a number of frameworks: Turbo, Stimulus, and Strada. On this publish, we’ll be Stimulus.
What’s Stimulus?
Stimulus is a JavaScript framework designed to work with static HTML and its current DOM parts. It lets customers add JavaScript performance to the DOM by connecting parts to Stimulus controllers, which can be utilized to control the DOM. Its purpose isn’t to supply a full JavaScript frontend, however moderately to reinforce current HTML parts.
The stimulus-rails
gem is shipped by default with Rails 7, so you can begin utilizing it in your purposes immediately!
RubyMine gives help for Stimulus, similar to code completion, navigation, and rename refactoring, which we encourage you to attempt as you make your means by way of the tutorial.
Tutorial: use Stimulus in Rails apps with RubyMine
On this tutorial, we’ll present you use the essential constructing blocks of Stimulus to simply combine JavaScript into your purposes. We’ll use a pattern Rails utility that permits the customers to make accounts, create microposts, comply with one another, and skim the microposts in a feed.
Clone the pattern Rails app
Observe these steps to clone and run our pattern app:
- Take a look at the pattern utility at https://github.com/JetBrains/sample_rails_app_7th_ed/tree/hotwire_setup (make sure that to modify to the
hotwire_setup
department when you’ve cloned the venture). For additional info on arrange a Git repository, please see the documentation. - Specify the Ruby interpreter and set up the gems.
Let’s discover Stimulus in motion by constructing a easy Copy to clipboard button.
Copy to clipboard button
Let’s add a Copy to clipboard button subsequent to our Delete hyperlink. The supposed operate of this new button is to repeat the textual content of the micropost after we click on on it.
1. Open the _micropost.html.erb
file and add the button to the view:
<% if current_user?(micropost.consumer) %> <%= link_to "delete", micropost, information: { "turbo-method": :delete, turbo_confirm: "You certain?" } %> <% finish %> <%= button_tag "copy", class: "btn btn-link button-link-aligned" %>
To repeat the textual content with a single mouse click on, we’ll want to make use of JavaScript. To try this, let’s join our button to a Stimulus controller.
2. Execute the next command utilizing RubyMine’s Run Something characteristic (Ctrl+Ctrl): rails generate stimulus clipboard
This command will generate a Stimulus controller, which is the element that permits us to create a connection between our DOM parts and JavaScript.
The identify of our controller is clipboard
. This command generates a file named clipboard_controller.js
within the app/javascript/controllers
listing. The controllers from this listing are loaded routinely (see the file index.js
).
3. Within the file _micropost.html.erb
, add the data-controller
attribute:
<li id="micropost-<%= micropost.id %>" data-controller="clipboard"> ... </li>
It will permit us to attach our micropost to the clipboard controller. You’ll be able to test if we efficiently related to the controller by including some debug logging into the join methodology after which checking the browser console upon loading the web page.
4. Replace the copy button in _micropost.html.erb
:
<%=button_tag "copy", class: "btn btn-link button-link-aligned", information: { motion: "clipboard#copy"} %>
After we click on on the button, we wish to carry out a particular motion, specifically, copying some textual content. That textual content ought to come from a sure goal, the physique of the micropost. Actions and targets are a number of the core ideas of Stimulus.
Actions join controller strategies to DOM occasions. While you click on on a component, enter some textual content, or submit a type, you’ll be able to invoke some JavaScript code by specifying a controller methodology utilizing the data-action
attribute. That is precisely what we did with our button within the code above.
5. Add the copy methodology to the clipboard controller:
export default class extends Controller { join() { } copy() { } }
To repeat the textual content, we will use the navigator.clipboard.writeText
methodology, besides we’d like a way of acquiring the factor from which the textual content is to be copied. That is the place targets turn out to be useful.
6. Add a goal to your controller by pasting the next line into your controller class:
static targets = ["source"];
Targets allow you to reference DOM parts that you simply would possibly wish to manipulate in your controller.
You’ll be able to specify which targets your controller goes to be utilizing inside a static discipline within the controller class.
7. Wrap the content material of your micropost in a div
tag in _micropost.html.erb
:
<div data-clipboard-target="supply"> <%= micropost.content material %> </div>
We are able to check with controller targets inside our HTML through the use of the data-[controller-name]-target
attribute, e.g. data-clipboard-target = "supply"
.
8. Full the physique of the copy
methodology:
// clipboard_controller.js copy() { navigator.clipboard.writeText(this.sourceTarget.textContent); }
We are able to use this.sourceTarget
to check with the goal inside our JavaScript controller.
Please be aware that navigator.clipboard
is simply out there in safe contexts. For native growth, you’ll be able to run your app on localhost.
That’s it! Now we will copy the content material of our microposts to the clipboard with a easy button click on.
Conceal a micropost from the feed
Different vital Stimulus ideas embody values, lessons, and shops.
You would possibly wish to cross some values as attributes of the controller factor and use these values in your JavaScript code. That is precisely what Stimulus values are designed to do. Specify them subsequent to the data-controller
attribute as follows:
<li id="micropost-<%= micropost.id %>" data-controller="clipboard" data-clipboard-copyable-value="true">
Right here, clipboard
is the identify of the controller, and copyable
is the identify of the property that we’d prefer to learn (or write) within the controller. Then, you outline the worth names and kinds within the controller in a particular static object, as proven under:
// clipboard_controller.js static values = { copyable: Boolean };
For additional details about out there varieties, please seek the advice of the documentation.
You’ll be able to reference the values in your JavaScript code as this.[valueName]Worth
:
// clipboard_controller.js if (!this.copyableValue) { ... }
Retailers allow you to reference different Stimulus controllers and parts from inside your controller: This fashion, completely different controllers in your venture can talk between themselves.
Lessons check with CSS lessons: You’ll be able to manipulate them programmatically out of your JavaScript code. Let’s take a more in-depth have a look at work with them by implementing a controller that may conceal microposts on our feed with a single click on. The identical impact may be achieved by straight manipulating the type of the factor (goal.type.show = "none"
), however we’ll accomplish this by setting the CSS class of the factor as a substitute. We are able to reuse this method for a lot of different visible results, too.
1. Open the customized.scss
file and add the next class:
.invisible { show: none }
2. Generate a controller to control the visibility of posts: rails generate stimulus visibility
.
3. Open the file visibility_controller.js
and add a category and a goal to the controller:
import { Controller } from "@hotwired/stimulus" export default class extends Controller { static lessons = ["hidden"]; static targets = ["hide"]; }
4. Add a conceal
methodology to the controller:
export default class extends Controller { ... conceal() { this.hideTarget.classList.add(this.hiddenClass); } }
This methodology will then append the CSS class hidden
to the goal conceal
.
5. Add the brand new controller and the category to the micropost view template by including the next HTML attributes:
<li id="micropost-<%= micropost.id %>" data-controller="clipboard visibility" data-visibility-hidden-class="invisible" data-visibility-target="conceal">
First, we add one other controller: data-controller="clipboard visibility"
. Second, we specify which precise CSS class the logical class from the controller corresponds to: data-visibility-hidden-class="invisible"
. Lessons have to be specified on the identical parts because the controllers to which they belong. Third, we specify the goal that we wish to conceal, which is your complete micropost.
6. Add a conceal button to the fitting of every micropost in _micropost.html.erb
:
<span class="timestamp"> ... <%= button_tag "conceal", class: "btn btn-link button-link-aligned", information: { motion: "visibility#conceal" }, type: "float: proper;" %> </span>
The button makes use of Stimulus actions to hook up with the controller methodology conceal.
If we click on on this button, the corresponding micropost will disappear.
…till we refresh the web page.
There are numerous methods to strategy persisting the hidden state of a micropost right here. For instance, you possibly can use Stimulus values and create a boolean worth named hidden
. Then, the hidden class can be routinely added to these parts for which the worth is true. Alternatively, you possibly can merely select to not load such microposts from the database. To try this, although, we’ll want to speak one thing again to our Rails app, which we will do by sending a easy request. Let’s revisit our conceal
methodology within the Stimulus controller.
7. Add the next code to the conceal
methodology in visibility_controller.js
:
conceal(e) { this.hideTarget.classList.add(this.hiddenClass); const id = e.goal.dataset.id const csrfToken = doc.querySelector("[name='csrf-token']").content material fetch(`/microposts/${id}/conceal`, { methodology: 'POST', headers: { 'Content material-Kind': 'utility/json', 'X-CSRF-Token': csrfToken }, physique: JSON.stringify({ hidden: true }) }).then(response => response.json()) }
We’re now sending a really primary POST request to microposts/:id/conceal
. You may ship something within the physique of the request, however right here, we’ll merely state that hidden
is now true.
Discover that this code makes use of the micropost ID, which it should obtain from the view.
8. Cross the ID within the information hash subsequent to the motion in _micropost.html.erb
:
<%= button_tag "conceal", class: "btn btn-link button-link-aligned", information: { motion: "visibility#conceal", id: micropost.id }, type: "float: proper;" %>
9. Add the next path to routes.rb
:
publish 'microposts/:id/conceal', to: 'microposts#conceal'
10. Add a conceal
methodology to microposts_controller.rb
:
def conceal @micropost = Micropost.discover(params[:id]) hidden_post = HiddenPost.new hidden_post.consumer = current_user hidden_post.micropost = @micropost hidden_post.save finish
11. Use Run Something to generate a mannequin that may retailer details about hidden posts for a particular consumer:
rails generate mannequin HiddenPost consumer:references micropost:references
12. Replace the Person#feed
methodology within the consumer.rb
file:
# consumer.rb def feed following_ids = "SELECT followed_id FROM relationships WHERE follower_id = :user_id" hidden_posts_for_user = "SELECT micropost_id FROM hidden_posts WHERE user_id = :user_id OR user_id IN (#{following_ids})" Micropost.the place("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: id) .the place("id NOT IN (#{hidden_posts_for_user})", user_id: id) .contains(:consumer, image_attachment: :blob) finish
Now that we’ve saved the details about hidden posts within the database, these will now not be seen within the consumer feed, even after a web page refresh.
Conclusion
On this tutorial, we’ve explored the Stimulus framework and its core ideas: controllers, targets, and actions. We’ve discovered to make use of Stimulus in our Rails purposes to simply join our DOM parts to JavaScript.
Benefit from Hotwire help in your favourite JetBrains IDE for Ruby and Rails. Obtain the most recent RubyMine model from our web site or by way of the free Toolbox App.
To study concerning the latest options as they arrive out, please comply with RubyMine on X.
We invite you to share your ideas within the feedback under and to counsel and vote for brand new options within the problem tracker.
Subscribe to RubyMine Weblog updates