Gems, MVC, Rails, Ruby, TwitterBootstrap

Embedding Devise Forms in Twitter Bootstrap Modals

In my previous post Top 10 Gems for new Rails Devs, I covered both the Devise and Twitter Bootstrap gems. Each of these gems is great at what they respectively do (authentication, design/styling). In this post, I’ll bring @plataformatec and @seyhunak‘s gifts together and easily put Devise sign-in and sign-up forms into Twitter Bootstrap modals.

defaults

What is a modal? If you aren’t familiar with modals, they are basically “pop-ups” or “prompts” that take a priority position in the user experience. If you’re interested in more theory regarding when and how to use modals, check out this post.

Getting sign-in and sign-up modals working in your application is not only a great introduction to using modals, but I think this feature creates a quality “first impression” for site visitors as well.

Want to see this code in a working repo? I’ll be orienting this post around a working implementation of this feature at www.social-playlist.com. This is a site I built with my good friend @lostincode. The project is open-source, so if you want to see everything in-context you can do so at https://github.com/lostincode/social-playlist.

Okay, let’s get started…

STEP 1:  BUILD THE MODAL PARTIALS
Partials are basically re-usable pieces of code falling into the the View portion of MVC. (For a Rails 4-specific explanation for MVC, check out my other post Reading Rails 4: MVC and Scaffolding for Rails Newbs.

Partials in Rails are easily identifiable based on the preceding underscores _ in file names (Example: _partial.html.erb). If you’ve ever run a rails g scaffold, you’ve created a partial named _form.html.erb. This single form is used in both the new and edit views for your scaffolded model. Whether you are creating a new record in the database or editing an existing record, you likely want access to all the same fields. Given the overlap, a single partial can serve in both conditions.

Okay, now let’s build modal partials for today’s feature…

We’re going to need to create some new files and there’s no hard requirements about where they go in your app. I think you definitely want them somewhere in your app/views/ hierarchy, but exactly where after that is up to you.

In many of my projects I use a “welcome controller” and associated views for things like the home page or “about us” page. As such, I think app/views/welcome/ makes a great spot for the below two files.

_login_modal.html.erb

_sign_up_modal.html.erb

Here’s a copy-paste of what I place into each file:

app/views/welcome/_login_modal.html.erb

<div class="modal hide fade in" id="login">

<div class="modal-header">

<button class="close" data-dismiss="modal">x</button>

<h2>Sign in</h2>

</div>

<div class="modal-body">

<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>

<div><%= f.label :email %><br />

<%= f.email_field :email, :autofocus => true %></div>

<div><%= f.label :password %><br />

<%= f.password_field :password %></div>

<% if devise_mapping.rememberable? -%>

<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>

<% end -%>

<%= f.submit "Sign in", :class => 'btn btn-small btn-success' %>

<% end %>

</div>

<div class="modal-footer">

<%= render "devise/shared/links" %>

</div>

</div>

Newb Note! The studious reader will have identified a sub-partial embedded within the partial we just created. Inspect the following statement:

<%= render "devise/shared/links" %>

That’s calling a partial into our partial! Don’t worry if you don’t fully understand just yet, it will all get clearer before we’re done.

Let’s get back to building our own partials. The second and final file we’ll need to create is:

app/views/welcome/_sign_up_modal.html.erb

<div class="modal hide fade in" id="sign_up">

<div class="modal-header">

<button class="close" data-dismiss="modal">x</button>

<h2>Sign Up</h2>

</div>

<div class="modal-body">

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>

<%= devise_error_messages! %>

<div><%= f.label :email %><br />

<%= f.email_field :email, :autofocus => true %></div>

<div><%= f.label :password %><br />

<%= f.password_field :password %></div>

<div><%= f.label :password_confirmation %><br />

<%= f.password_field :password_confirmation %></div>

</div>

<div class="modal-footer">

<p><div><%= f.submit "Sign up", :class => 'btn btn-small btn-success' %></div></p>

<p><a href="#" class="btn btn-small" data-dismiss="modal">Close</a></p>

</div>

<% end %>

</div>

NEWB NOTE! When creating modals in Twitter Bootstrap, make sure to use their built in classes for header, body, and footer. These control margins/padding that help things look just right.

Okay, back to business. Let’s get those partials working for us.

STEP 2: RENDER THE PARTIALS INTO APPLICATION LAYOUT
Remember above when I highlighted the partial-within-a-partial? The sub-partial was invoked using:

<%= render "devise/shared/links" %>

The reason I belabor the point is to establish a universal trend – and here it is…To render any partial, simply call render along with the location of the partial.

In our case, we have sign-in and sign-up buttons in the navbar on every page of our web site. As is the Rails way, we place app-wide View content in app/views/layouts/application.html.erb. Similarly, we want our new pop-up modals available (visible or not) on every page of our site. Accordingly, we put the below code into app/views/layouts/application.html.erb also:

<%= render "welcome/login_modal" %>

<%= render "welcome/sign_up_modal" %>

Newb Note! You might be thinking, “hey, that looks like a typo…aren’t partials pre-fixed with an underscore like _partial.html.erb ?” That’s not a typo, that’s simply the Rails convention for refering to partial location. Also, we do not need to supply the app/views/ elements of the directory path when refering to the location of partials. Rails confidently expects them to be in the V of MVC!

Where exactly should this render code be placed in app/views/layouts/application.hmtl.erb? Again, there’s not much of a hard and fast rule. Personally, I put mine immediately under the  <body> open div.

STEP 3: UPDATE YOUR LINK_TOs
We’re not leaving app/views/layout/application.html.erb yet. Now we need to update our sign-in and sign-up buttons to engage our newly created modals as opposed to their historical forms. We can do this by simply changing the relevant link_to‘s to look like the below.

<%= link_to "Login", "#login", "data-toggle" => "modal", :class => 'btn btn-small' %>

<%= link_to "Sign up", "#sign_up", "data-toggle" => "modal", :class => 'btn btn-small btn-success' %>

Newb Note! The first time I implemented this feature, I placed the above code next to the existing link_to‘s. I did this to make sure everything was working with the new before getting rid of the old way.

One of the critical pieces of any link_to is the second argument – in our case, #login and #sign_up. The values provided here must match the id in the parent <div> of the associated partials. To make sure I’m clear, the relevant code from the parent <div>s are shown here again.

<div class="modal hide fade in" id="login">

<div class="modal hide fade in" id="sign_up">

STEP 4: ADD SOME JAVASCRIPT MAGIC
Everything is just about ready to rock. When I first got this working in my app, I was disappointed that while the modals were popping up, they were dark like the subordinated background. Luckily, this StackOverflow post suggested adding the below into app/views/layouts/application.html.erb

<script type="text/javascript"> $(function ()

{ $("#myModal").modal({show:false }); </script>

If you’re like me, you’re thinking “where exactly should I put that code?”. Kindly the SO post also suggests putting it “right before the </head >” close tag.

STEP 5: UPDATE YOUR APPLICATION HELPER
Okay, so we’ve forms that users want to see. We’ve established a call to render them on every page of our application – next we need to make sure a new resource (the Devise term for user) is instantiated when our modal is engaged.

Thankfully the esteemed Pablo who originally wrote this entry (the birthplace of some succinctly powerful methods and now hosted on the official Devise wiki), provides us the below helper methods to place in app/helpers/application_helpers.rb.

def resource_name

:user

end

def resource

@resource ||= User.new

end

def devise_mapping

@devise_mapping ||= Devise.mappings[:user]

end

STEP 6: ENJOY!
You’re done! Fire up a rails s and check it out in the browser before you git push.

Hopefully you’ve enjoyed and found value in this post. If so, drop me a comment or a tweet @mxstrand! Also, here’s a few other posts you might like:

Thanks for reading.

2 thoughts on “Embedding Devise Forms in Twitter Bootstrap Modals

Leave a reply to ivanoats Cancel reply