`

Creating a 100% ajax CRUD using rails 3 and unobtrusive javascript

 
阅读更多

Creating the project and setting the Gemfile

Edited: Just corrected the misspelling on the title "unobtrusive", sorry for that** Ps: I'm using the latest rails 3 beta version while coding**

$ rails -v
Rails 3.0.0.beta4

Creating the project:

$ rails new ajax_on_rails -d mysql

Setting up the Gemfile

I'm setting the nifty-generators here, just to generate our main CRUD.

source 'http://rubygems.org'
gem 'rails', '3.0.0.beta4'
gem 'mysql'
gem 'nifty-generators'

Generating the layout scaffold

$ rails g nifty:layout
$ rails g nifty:scaffold Post title:string content:text
$ rake db:create
$ rake db:migrate

If you run your server and go to the "/posts" you will see a common scaffold.

Changing the CRUD for an unique form

So... we need to change some little things. We gonna create a unique form in "/posts". Inside that form we gonna make everything with ajax: list, create, edit and delete. So first we need to change our Post controller to make everything works:

def index
  @posts = Post.all
  @post = Post.new
end

def create
  @posts = Post.all
  @post = Post.new(params[:post])
  if @post.save
    flash[:notice] = "Successfully created post."
    redirect_to posts_url
  else
    render :action => 'index'
  end
end

def edit
  @posts = Post.all
  @post = Post.find(params[:id])
  render :action => "index"
end

def update
  @posts = Post.all
  @post = Post.find(params[:id])
  if @post.update_attributes(params[:post])
    flash[:notice] = "Successfully updated post."
    redirect_to posts_url
  else
    render :action => 'index'
  end
end

def destroy
  @post = Post.find(params[:id])
  @post.destroy
  flash[:notice] = "Successfully destroyed post."
  redirect_to posts_url
end

Making a basic refactoring creating a method to load some objects before every action:

before_filter :load

def load
  @posts = Post.all
  @post = Post.new
end

def index
end

def create
  @post = Post.new(params[:post])
  if @post.save
    flash[:notice] = "Successfully created post."
    redirect_to posts_url
  else
    render :action => 'index'
  end
end

def edit
  @post = Post.find(params[:id])
  render :action => "index"
end

def update
  @post = Post.find(params[:id])
  if @post.update_attributes(params[:post])
    flash[:notice] = "Successfully updated post."
    redirect_to posts_url
  else
    render :action => 'index'
  end
end

def destroy
  @post = Post.find(params[:id])
  @post.destroy
  flash[:notice] = "Successfully destroyed post."
  redirect_to posts_url
end
end

As you can see we are not using the "new" and "show" methods anymore Now we need to change our index template to render the post form, we can do that adding a partial:

app/views/posts/_form.erb

<%= form_for @post do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :title %><br/>
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :content %><br/>
    <%= f.text_area :content, :rows => 5 %>
  </p>
  <p><%= f.submit %></p>
<% end %>

And we render this one in our index file:

spp/views/posts/index.html.erb

<% title "Posts" %>

<%= render :partial => 'form' %>

<table>
  <tr>
    <th>Title</th>
    <th>Content</th>
  </tr>
  <% for post in @posts %>
    <tr>
      <td><%= post.title %></td>
      <td><%= post.content %></td>
      <td><%= link_to "Show", post %></td>
      <td><%= link_to "Edit", edit_post_path(post) %></td>
      <td><%= link_to "Destroy", post, :confirm => 'Are you sure?', :method => :delete %></td>
    </tr>
  <% end %>
</table>

<p><%= link_to "New Post", new_post_path %></p>

It should be working now with a unique view. We are not using the "show.html.erb", "new.html.erb" and "edit.html.erb" files anymore, feel free to delete it. Before we reach the next part, let's add some validation in our model, we gonna need that later:

class Post < ActiveRecord::Base
  attr_accessible :title, :content

  validates_presence_of :title,:content
end

Changing from Prototype to Jquery

For default Rails implements ajax requests with prototype, we need to change it to work with jquery. First, download the rails.js equivalent with jquery from github . Copy the rails.js under the src folder to your public/javascripts/. In our layout "application.html.erb" we'll change the next lines:

<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>

to

<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js' %>
<%= javascript_include_tag 'rails' %>

It's time to the ajax magic

Keep it simple, let's think about what we want:

  • Our controller and links should make remote requests
  • Our html should contain divs so we can change the content with unobstructive javascripts.
  • Our actions should return js (javascript) content to change the html page.

So let's start changing everything again. The template(layout) need to contain a div to show the flash_notice:

<body>
  <div id="container">
    <div id="flash_notice" style="display:none"></div>
    <%= content_tag :h1, yield(:title) if show_title? %>
    <%= yield %>
  </div>
</body>

Put some partials in our index and add the remote => true in our links and forms:

<% title "Posts" %>

<div id="post_form"><%= render :partial => 'form' %></div>
<div id="posts_list"><%= render :partial => "posts" %></div>

app/views/posts/_form.html.erb

I also put a div to show the errors here, so we can change it in our js responses:

<%= form_for(@post, :remote => true) do |f| %>
  <div id= "post_errors" style="display:none"></div>
  <p>
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :content %><br />
    <%= f.text_area :content, :rows => 5 %>
  </p>
  <p><%= f.submit %></p>
<% end %>

app/views/posts/_posts.html.erb

<table>
  <tbody><tr>
    <th>Title</th>
    <th>Content</th>
  </tr>

  <% @posts.each do |post| %>
    <tr>
      <td><%= post.title %></td>
      <td><%= post.content %></td>
      <td><%= link_to "Edit", edit_post_path(post), :remote => true %></td>
      <td><%= link_to "Destroy", post, :remote => true, :confirm => 'Are you sure?', :method => :delete %></td>
    </tr>
  <% end %>

  </tbody>
</table>

I created this partial so i can update the list of posts with javascript too:

<table>
  <tr>
    <th>Title</th>
    <th>Content</th>
  </tr>
  <% for post in @posts %>
    <tr>
      <td><%= post.title %></td>
      <td><%= post.content %></td>
      <td><%= link_to "Edit", edit_post_path(post), :remote => true %></td>
      <td><%= link_to "Destroy", post, :remote => true, :confirm => 'Are you sure?', :method => :delete %></td>
    </tr>
  <% end %>
</table>

We need to change our controller too. Since we gonna make a 100% ajax CRUD we don't need that redirects anymore:

class PostsController < ApplicationController

  before_filter :load

  def load
    @posts = Post.all
    @post = Post.new
  end

  def index
  end

  def create
    @post = Post.new(params[:post])
    if @post.save
      flash[:notice] = "Successfully created post."
      @posts = Post.all
    end
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
    @post = Post.find(params[:id])
    if @post.update_attributes(params[:post])
      flash[:notice] = "Successfully updated post."
      @posts = Post.all
    end
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    flash[:notice] = "Successfully destroyed post."
    @posts = Post.all
  end
end

Almost there. If you try to use the form now, nothing happens right? If you take a look at the console(server) you will find some errors telling you Rails can't find the view js to render. So let's create this files. Basically we gonna create a view to render javascript, with this javascript we gonna inject or modify our html. We are using jquery to do the modification/injection part, so if you never work with that take a look at the official site to learn a lot of cool stuffs: http://www.jquery.com We need files to create, edit, update and destroy actions, so let's create them:

app/views/posts/create.js.erb

Here we verify if the @post object contains errors and changes the behavior according to that:

<% if @post.errors.any? -%>
  /*Hide the flash notice div*/
  $("#flash_notice").hide(300);

  /*Update the html of the div post_errors with the new one*/
  $("#post_errors").html("<%= escape_javascript(error_messages_for(@post))%>");

  /*Show the div post_errors*/
  $("#post_errors").show(300);
<% else -%>
  /*Hide the div post_errors*/
  $("#post_errors").hide(300);

  /*Update the html of the div flash_notice with the new one*/
  $("#flash_notice").html("<%= escape_javascript(flash[:notice])%>");

  /*Show the flash_notice div*/
  $("#flash_notice").show(300);

  /*Clear the entire form*/
  $(":input:not(input[type=submit])").val("");

  /*Replace the html of the div post_lists with the updated new one*/
  $("#posts_list").html("<%= escape_javascript( render(:partial => "posts") ) %>");
<% end -%>

app/views/posts/edit.js.erb

In this action we just need to update the form with the select post.

$("#post_form").html("<%= escape_javascript(render(:partial => "form"))%>");

app/views/posts/update.js.erb

<% if @post.errors.any? -%>
  $("#flash_notice").hide(300);
  $("#post_errors").html("<%= escape_javascript(error_messages_for(@post))%>");
  $("#post_errors").show(300);
<% else -%>
  $("#post_errors").hide(300);
  $("#flash_notice").html("<%= escape_javascript(flash[:notice])%>");
  $("#flash_notice").show(300);
  $(":input:not(input[type=submit])").val("");
  $("#posts_list").html("<%= escape_javascript( render(:partial => "posts") ) %>");
<% end -%>

app/views/posts/destroy.js.erb

$("#post_errors").hide(300);
$("#flash_notice").html("<%= escape_javascript(flash[:notice])%>");
$("#flash_notice").show(300);
$("#posts_list").html("<%= escape_javascript( render(:partial => "posts") ) %>");

And that's it, go to your "/posts" page and you should see our 100% ajax CRUD.

Ps1: That uses html5 to make our forms and links remotes (:remote => true), so it's not gonna work in any version of INTERNET EXPLORER yet.

Ps2: You can also use the redirect/render in your actions pointing to the index and then create only one javascript view (index.js.erb) treating that as you want. I prefer to keep things separated in case I decide to change the visual behavior of some view.

Ps3: Someone should make a generator for this ajax forms.

分享到:
评论

相关推荐

    简单的ajax异步Crud项目

    Ajax(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下,能够更新部分网页内容的技术。它的核心在于JavaScript,通过创建XMLHttpRequest对象与服务器进行异步通信,实现了用户界面与后台数据的...

    yii2-ajaxcrud-assets:yii2-ajaxcrud扩展的资产捆绑包

    Yii2-AjaxCRUD-Assets 是一个专门为 Yii2 框架设计的扩展,它提供了对 AJAX CRUD(创建、读取、更新、删除)操作的支持,并优化了用户体验。这个扩展的核心在于其资产捆绑包,它包含了必要的 JavaScript 和 CSS 文件...

    yii2-ajaxcrud, 用于yii2的单一页面Ajax管理的Gii模板.zip

    yii2-ajaxcrud, 用于yii2的单一页面Ajax管理的Gii模板 yii2-ajaxcrud 用于yii2的单一页面Ajax管理的Gii模板 特性使用Ajax创建。读取。更新。删除页面批量删除 suportPjax小部件 suport导出函数( pdf,html,文本,cs

    yii2-ajaxcrud:yii2-ajaxcrud personalizado

    3. **数据验证**:Yii2 自带的数据验证机制可以应用于 AjaxCRUD,确保输入数据的有效性和安全性。 4. **分页与排序**:支持表格数据的分页显示和动态排序,用户可以方便地浏览大量数据。 5. **表单提交与验证**:...

    Ajax-Spring-MVC-CRUD-form-submit-and-ajax.zip

    Ajax-Spring-MVC-CRUD-form-submit-and-ajax.zip,spring mvc crud应用程序(springmvc、hibernate 4.x、bootstrap 3.x、jquery、mysql),ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json...

    ajax-crud-bootstrap:带有Bootstrap UI的Ajax CRUD

    AJAX CRUD BOOTSTRAP 是具有Bootstrap UI的Ajax Crud,包括活动记录类和简单ORM模型。 对于使用Active Record,您可以在github 库中看到。 这个包含的示例可以看到example.php文件和example_model.php文件。 ID ...

    crud-php-ajax.zip_ajax php_crud php ajax_php ajax

    接着是AJAX(Asynchronous JavaScript and XML),它不是一种单一的技术,而是一种使用一组相关技术来创建动态Web应用程序的方法。通过AJAX,前端可以向服务器发送异步请求,获取数据并在用户界面上更新,而无需刷新...

    Laravel开发-ajax-crud-generator

    首先,我们要理解Ajax(Asynchronous JavaScript and XML)的核心概念。它允许在不重新加载整个网页的情况下与服务器交换数据并更新部分网页内容。在Laravel框架中,Ajax能够与后端路由和控制器紧密协作,实现实时的...

    crud:一个简单的 jQuery AJAX crud 应用程序

    在这个名为"crud"的jQuery AJAX应用程序中,我们将深入探讨如何使用JavaScript和jQuery的AJAX功能来实现对后端数据的无刷新交互。 首先,让我们了解一下jQuery库。jQuery是一个轻量级的JavaScript库,它简化了HTML...

    Ajax-laravel-jquery-ajax-crud.zip

    Ajax-laravel-jquery-ajax-crud.zip,用jquery的ajax特性简单实现laravel crud,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建动态网页,其中网页的小部分...

    SSM+maven+ajax简单CRUD视频

    简单的SSM crud视频 前端用到大量的ajax 后端返回json数据 可移植性

    [Rails 常用插件简介]CRUD Generator 2

    **Rails 常用插件简介 - CRUD Generator 2** 在Ruby on Rails框架中,开发过程中经常需要创建、读取、更新和删除(CRUD)数据。为了提高开发效率,开发者通常会使用各种插件来自动化这个过程。CRUD Generator 2就是...

    rails-4-ajax-crud-via-jquery:如何通过jQuery在Rails 4中进行Ajax Crud的示例应用程序

    这是一个示例应用程序,说明如何通过jQuery在Ajax Crud 4中进行操作。 我们利用$ .getJSON和$ .ajax进行AJAX。 我们没有使用不引人注目JavaScript或模板。 应用程序的根发送到静态控制器的index操作。 因此,请...

    Ruby Rails 3 Linda

    学习如何使用`remote: true`选项创建Ajax链接和表单,以及使用Unobtrusive JavaScript(UJS)驱动JavaScript行为。 11. **Caching**:Rails提供了多种缓存策略,如页面缓存、动作缓存、碎片缓存和Dalli(Memcached...

    Object_SpringBoot-Ajax_CRUD.rar

    4. **Ajax**:Ajax(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下,能够更新部分网页的技术。在本项目中,前端通过Ajax发送异步请求到后端,处理CRUD操作,返回JSON格式的数据,而不是传统的...

    RailsAjaxCRUD:使用 jquery ajax 执行所有 CRUD 操作的 Rails 4 应用程序

    Rails 4 jquery Ajax 示例 ###演示 这是一个如何使用ajax进行CRUD操作的小示例。 安装它 git clone :sagarjunnarkar/RailsAjaxCRUD.git cd RailsAjaxCRUD 捆绑安装 配置 config/database.yml 耙数据库:设置 ...

    Ajax-codeigniter-ajax-crud.zip

    Ajax-codeigniter-ajax-crud.zip,使用codeigniter、jquery和ajax实现简单的crud,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建动态网页,其中网页的小...

    Laravel开发-ajax-crud-generator .zip

    Ajax(Asynchronous JavaScript and XML)则是一种创建交互式网页应用的技术,通过在后台与服务器进行少量数据交换,实现了页面的异步更新。CRUD(Create, Read, Update, Delete)是数据库操作的基本动作,用于管理...

Global site tag (gtag.js) - Google Analytics