Ruby 于 Rails:使用 bootstrap 模态制作注册表单的最佳方法是什么?
Ruby on Rails: What is the best way to make a registration form using a bootstrap modal?
我正在尝试使用 bootstrap 模式弹出窗口为 Rails 应用程序上的 Ruby 创建注册表单。我自己从头开始对表单进行硬编码(没有使用 SimpleForm 或 Devise)。当我点击提交时,我似乎无法让数据通过。
这里是 users_controller.rb:
class UsersController < ApplicationController
#before_action :confirm_logged_in
respond_to :html, :js
def index
@users = User.all.sorted
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
respond_to do |format|
format.html { redirect_back }
format.js
end
if @user.save
flash[:success] = 'Welcome, #{@user.first_name}!'
else
render('new')
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update_attributes(user_params)
flash[:success] = 'You have been updated.'
redirect_to(:action => 'show')
else
render('edit')
end
end
def delete
@user = User.find(params[:id])
end
def destroy
@user = User.find(params[:id]).destroy
flash[:notice] = '#{@user.first_name} #{@user.last_name} has been deleted.'
redirect_to ('home')
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :confirm_password, :avatar)
end
end
这里是放置模态框的view/layouts/application.html.erb:
<button id="signupButton" data-toggle="modal", data-target="#registerModal">
<span class="glyphicon glyphicon-user"></span>
<%= link_to 'Register', new_user_path, remote: true %>
</button>
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="registerModalTitle" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<!-- REGISTER FORM -->
<%= render 'users/register' %>
<!-- END REGISTER FORM -->
</div>
</div>
</div>
</nav>
<!-- END NAVBAR -->
最后是表格 partial (_register.html.erb):
<div class="modal-body">
<%= form_for :user, remote: true do |f| %>
<div class="form-group has-success has-feedback">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field(:first_name, class: "form-control", placeholder: "First Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field(:last_name, class: "form-control", placeholder: "Last Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :email, class: "sr-only" %>
<%= f.text_field(:email, class: "form-control", placeholder: "Email") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Confirm Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="modal-footer">
<%= link_to 'Close', "#", class: "btn btn-default", data: {dismiss: "modal"} %>
<%= f.submit 'Register', class: 'btn btn-primary' %>
</div>
<% end %>
</div>
这是我的 routes.rb 文件:
Rails.application.routes.draw do
get '/users', to: 'users#index'
root 'access#index', as: '/'
get '/home', to: 'home#home'
#match ':controller(/:action(/:id))', :via => [:get, :post]
resources :users
resources :sessions
end
这是我的 user.rb 模型:
class User < ActiveRecord::Base
has_secure_password
before_save { self.email = email.downcase }
validates :first_name, :presence => true,
:length => { :maximum => 25 }
validates :last_name, :presence => true,
:length => { :maximum => 50 }
VALID_EMAIL_REGEX = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}\Z/i
validates :email, :presence => true,
:uniqueness => { case_sensitive: false},
:length => { :maximum => 100 },
:format => { with: VALID_EMAIL_REGEX },
:confirmation => true
validates :password, :presence => true,
:length => { :within => 6..20 }
validates_confirmation_of :password
#mount_uploader :picture, PictureUploader
#validate :picture_size
validates :avatar, :attachment_presence => true
validates_with AttachmentPresenceValidator, :attributes => :avatar
validates_with AttachmentSizeValidator, :attributes => :avatar, :less_than => 1.megabytes
scope :sorted, lambda { order("last_name ASC, first_name ASC") }
def name
"#{first_name} #{last_name}"
end
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, " must be less than 5MB")
end
end
end
这就是您通过 ajax 加载表单并将其注入 bootstrap modal 的方式。请注意,这是基于 scaffolded rails app - 您需要根据自己的应用进行调整。
1。设置页面特定 javascript
更改 views/application/layout.html.erb
中的 body 标签
<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">
然后我们在 assets/javascripts/application.js
中设置一个侦听器,它告诉我们哪个页面已加载。
// This lets us bind "page specific javascript" by listening for the controller:action:loaded event.
$(document).on('page:change', function(){
var data = $('body').data();
var key = data['controller'] + ':' + data['action'] + ':loaded';
console.log('Triggering', key);
$(this).trigger(key);
});
这样我们就可以在主页上显示模式。如果您的模态不是“启动画面”,请随意跳过此步骤。
在我的示例中,我将 pages#home
作为根路径。
2。创建模态模板
在 views/layouts/_modal.html.erb
中创建通用模态模板。
<div class="modal fade" id="modal-template" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">Generic Modal Title</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
在您的 views/layouts/application.html.erb
中包含部分内容。
<!-- ... -->
</div> <!-- /container -->
<%= render partial: 'layouts/modal' %>
</body>
</html>
3。创建注册表单。
首先创建一个用户表单部分views/users/_form.html.erb
。
<%= form_for(@user) do |f| %>
<% if @user.errors.any? %>
<div id="form-errors">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-inputs">
<div class="form-group has-success has-feedback">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field(:first_name, class: "form-control", placeholder: "First Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field(:last_name, class: "form-control", placeholder: "Last Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :email, class: "sr-only" %>
<%= f.text_field(:email, class: "form-control", placeholder: "Email") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :confirm_password, class: "sr-only" %>
<%= f.password_field(:confirm_password, type: "password", class: "form-control", placeholder: "Confirm Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
然后将表格添加到您的 views/users/new.html.erb
。
<h1>New User</h1>
<%= render 'form' %>
<%= link_to 'Back', users_path %>
4。使用 Ajax.
加载表单
这看起来很复杂,但实际上并非如此。我们复制我们添加到页面的模态模板,并从我们使用 ajax.
加载的表单中注入组件
$(document).ready(function(){
// Only fire this on the home page.
// Replace this with a regular click handler if you do not want a "splash"
$(document).on('pages:home:loaded', function(){
// Load the page content from "/users/new"
var promise = $.get("/users/new");
// When the ajax request has finished
promise.success(function(data){
var $frag = document.createDocumentFragment(), // Good for performance
$modal = $($('#modal-template')[0].outerHTML, $frag),
$form = $($(data).find('#new_user')[0].outerHTML),
$btn = $form.find('input[type="submit"]');
// Wrap the modal content in the form.
// Give the modal a unique ID.
$modal.attr('id', 'register-modal');
// Add the inputs from the form inside the body
$modal.find('.modal-body').append($form);
// Customize the title
$modal.find('.modal-title').text('Sign Up!');
// Add the submit button next to the close button
$btn.addClass('btn btn-primary');
// since the button is not actually in the form we add an event handler to submit the form.
$btn.click(function(){
$modal.find('form').submit();
});
$modal.find('.modal-footer').append($btn);
// Attach the modal to document
$('body').append($modal);
// Open the modal
$modal.modal({});
});
promise.fail(function(jqXHR, textStatus, errorThrown){
console.error('Failed to fetch user registration form', textStatus, jqXHR, errorThrown);
});
});
});
我正在尝试使用 bootstrap 模式弹出窗口为 Rails 应用程序上的 Ruby 创建注册表单。我自己从头开始对表单进行硬编码(没有使用 SimpleForm 或 Devise)。当我点击提交时,我似乎无法让数据通过。
这里是 users_controller.rb:
class UsersController < ApplicationController
#before_action :confirm_logged_in
respond_to :html, :js
def index
@users = User.all.sorted
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
respond_to do |format|
format.html { redirect_back }
format.js
end
if @user.save
flash[:success] = 'Welcome, #{@user.first_name}!'
else
render('new')
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update_attributes(user_params)
flash[:success] = 'You have been updated.'
redirect_to(:action => 'show')
else
render('edit')
end
end
def delete
@user = User.find(params[:id])
end
def destroy
@user = User.find(params[:id]).destroy
flash[:notice] = '#{@user.first_name} #{@user.last_name} has been deleted.'
redirect_to ('home')
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :confirm_password, :avatar)
end
end
这里是放置模态框的view/layouts/application.html.erb:
<button id="signupButton" data-toggle="modal", data-target="#registerModal">
<span class="glyphicon glyphicon-user"></span>
<%= link_to 'Register', new_user_path, remote: true %>
</button>
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="registerModalTitle" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<!-- REGISTER FORM -->
<%= render 'users/register' %>
<!-- END REGISTER FORM -->
</div>
</div>
</div>
</nav>
<!-- END NAVBAR -->
最后是表格 partial (_register.html.erb):
<div class="modal-body">
<%= form_for :user, remote: true do |f| %>
<div class="form-group has-success has-feedback">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field(:first_name, class: "form-control", placeholder: "First Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field(:last_name, class: "form-control", placeholder: "Last Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :email, class: "sr-only" %>
<%= f.text_field(:email, class: "form-control", placeholder: "Email") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Confirm Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="modal-footer">
<%= link_to 'Close', "#", class: "btn btn-default", data: {dismiss: "modal"} %>
<%= f.submit 'Register', class: 'btn btn-primary' %>
</div>
<% end %>
</div>
这是我的 routes.rb 文件:
Rails.application.routes.draw do
get '/users', to: 'users#index'
root 'access#index', as: '/'
get '/home', to: 'home#home'
#match ':controller(/:action(/:id))', :via => [:get, :post]
resources :users
resources :sessions
end
这是我的 user.rb 模型:
class User < ActiveRecord::Base
has_secure_password
before_save { self.email = email.downcase }
validates :first_name, :presence => true,
:length => { :maximum => 25 }
validates :last_name, :presence => true,
:length => { :maximum => 50 }
VALID_EMAIL_REGEX = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}\Z/i
validates :email, :presence => true,
:uniqueness => { case_sensitive: false},
:length => { :maximum => 100 },
:format => { with: VALID_EMAIL_REGEX },
:confirmation => true
validates :password, :presence => true,
:length => { :within => 6..20 }
validates_confirmation_of :password
#mount_uploader :picture, PictureUploader
#validate :picture_size
validates :avatar, :attachment_presence => true
validates_with AttachmentPresenceValidator, :attributes => :avatar
validates_with AttachmentSizeValidator, :attributes => :avatar, :less_than => 1.megabytes
scope :sorted, lambda { order("last_name ASC, first_name ASC") }
def name
"#{first_name} #{last_name}"
end
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, " must be less than 5MB")
end
end
end
这就是您通过 ajax 加载表单并将其注入 bootstrap modal 的方式。请注意,这是基于 scaffolded rails app - 您需要根据自己的应用进行调整。
1。设置页面特定 javascript
更改 views/application/layout.html.erb
<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">
然后我们在 assets/javascripts/application.js
中设置一个侦听器,它告诉我们哪个页面已加载。
// This lets us bind "page specific javascript" by listening for the controller:action:loaded event.
$(document).on('page:change', function(){
var data = $('body').data();
var key = data['controller'] + ':' + data['action'] + ':loaded';
console.log('Triggering', key);
$(this).trigger(key);
});
这样我们就可以在主页上显示模式。如果您的模态不是“启动画面”,请随意跳过此步骤。
在我的示例中,我将 pages#home
作为根路径。
2。创建模态模板
在 views/layouts/_modal.html.erb
中创建通用模态模板。
<div class="modal fade" id="modal-template" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">Generic Modal Title</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
在您的 views/layouts/application.html.erb
中包含部分内容。
<!-- ... -->
</div> <!-- /container -->
<%= render partial: 'layouts/modal' %>
</body>
</html>
3。创建注册表单。
首先创建一个用户表单部分views/users/_form.html.erb
。
<%= form_for(@user) do |f| %>
<% if @user.errors.any? %>
<div id="form-errors">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-inputs">
<div class="form-group has-success has-feedback">
<%= f.label :first_name, class: "sr-only" %>
<%= f.text_field(:first_name, class: "form-control", placeholder: "First Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :last_name, class: "sr-only" %>
<%= f.text_field(:last_name, class: "form-control", placeholder: "Last Name") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :email, class: "sr-only" %>
<%= f.text_field(:email, class: "form-control", placeholder: "Email") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :password, class: "sr-only" %>
<%= f.password_field(:password, type: "password", class: "form-control", placeholder: "Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<div class="form-group has-success has-feedback">
<%= f.label :confirm_password, class: "sr-only" %>
<%= f.password_field(:confirm_password, type: "password", class: "form-control", placeholder: "Confirm Password") %>
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
然后将表格添加到您的 views/users/new.html.erb
。
<h1>New User</h1>
<%= render 'form' %>
<%= link_to 'Back', users_path %>
4。使用 Ajax.
加载表单这看起来很复杂,但实际上并非如此。我们复制我们添加到页面的模态模板,并从我们使用 ajax.
加载的表单中注入组件$(document).ready(function(){
// Only fire this on the home page.
// Replace this with a regular click handler if you do not want a "splash"
$(document).on('pages:home:loaded', function(){
// Load the page content from "/users/new"
var promise = $.get("/users/new");
// When the ajax request has finished
promise.success(function(data){
var $frag = document.createDocumentFragment(), // Good for performance
$modal = $($('#modal-template')[0].outerHTML, $frag),
$form = $($(data).find('#new_user')[0].outerHTML),
$btn = $form.find('input[type="submit"]');
// Wrap the modal content in the form.
// Give the modal a unique ID.
$modal.attr('id', 'register-modal');
// Add the inputs from the form inside the body
$modal.find('.modal-body').append($form);
// Customize the title
$modal.find('.modal-title').text('Sign Up!');
// Add the submit button next to the close button
$btn.addClass('btn btn-primary');
// since the button is not actually in the form we add an event handler to submit the form.
$btn.click(function(){
$modal.find('form').submit();
});
$modal.find('.modal-footer').append($btn);
// Attach the modal to document
$('body').append($modal);
// Open the modal
$modal.modal({});
});
promise.fail(function(jqXHR, textStatus, errorThrown){
console.error('Failed to fetch user registration form', textStatus, jqXHR, errorThrown);
});
});
});