ruby-on-rails - 详细说明 MVC 如何在 Rails 中工作,以及 Controller 如何与表单等通信?

标签 ruby-on-rails ruby-on-rails-3 model-view-controller

也许这甚至可以成为社区 Wiki,但我希望详细描述 Controller 的工作原理 - 或者更确切地说,我如何让它做我想让它做的事情。

我了解 MVC 的一般结构以及模型如何存储 db 结构,以及 Controller 与 db 交互并将信息传递给 View 。

然而,我对如何使用我的 Controller 完成简单的任务感到困惑(在基本层面上)。我知道如果我想为模型/对象创建一个新记录,我只需做 object = Object.new(:name => "Object Name")在 Rails 控制台中。

但是我到底要如何在 Controller 的 CRUD 元素中做到这一点,为什么?

请使用一个简单的例子 - 例如向用户展示他们的银行账户余额(我知道围绕这一点有很多复杂性,但为了这个解释而忽略它们)。模型会是什么样子(只包括:姓名、地址、交易类型(存款/取款)、余额)。

一个 View 会是什么样子? Controller 会是什么样子?您做出的任何选择(如使用表格)请解释它们。为什么要使用表单,而不是下拉菜单,以及(通俗地说)表单或下拉菜单如何与 Controller 交互?我如何将在那里捕获的信息获取到数据库中,为什么我要这样做?

我知道这听起来有很多问题,但我已经访问了 RailsTutorial.org,观看了许多 Railscast,阅读了 Rails 指南,并阅读了许多其他教程,但我对 Rails 的工作方式和原因的理解仍然存在一些基本差距。

提前致谢。

最佳答案

我不知道我还能提供多少帮助,但我理解你刚刚陷入困境的痛苦。 ghoppe 推荐的文章《瘦 Controller ,胖模型》很好的解释了 Ms Vs & Cs 的功能。鉴于这并不能完全回答您的问题,我将尝试解释每个结构的机制。

模型

class Account < ActiveRecord::Base
  belongs_to :user

  validates_presence_of :address

  def name              # Account does not have a name field, but User does so I will make a name method for Account and feed it name of the user it belongs to.
    user = self.user    # Account gets the user method with the <belongs_to :user> association
                        # note: Rails expects Accounts to have a user_id field so it can perform the "magic" to associate Accounts with Users 
    if user.name
      return user.name
    else
      return nil
    end
  end
end

该模型描述了您的对象。就像任何 OOP 语言中的对象一样,您希望将所有对象逻辑都放在这里。这包括用于关联(has_one,belongs_to,...)和验证的 rails 助手,以及您希望对象能够在整个模型 View 和 Controller 中使用的任何其他方法或库。

Controller
class AccountsController < ApplicationController
  before_filter :name, :only => :edit, :destroy  # @account.name will be executed before the edit or destroy method(action) can be invoked on @account.  If the user who has the account has a name the action will execute.  

  def index                                      # This is a RESTful action and is mapped by Rails by default to an HTTP GET request.  Rails expects an index.html.erb or index.haml.erb or index.something in the Accounts view to map this action to.
    @accounts = Account.all                      # @accounts is an instance variable and will be accessible in the view this action is mapped to.
  end   

  def show
    @account = Account.find(params[:id])         # params[:id] is passed to the controller from the view. The params hash is the primary tool form moving data from a form or URL into a controller.  Anytime you click on the link_to the show or edit action of an object Rails will put that objects id in the params hash and call the appropriate action in that objects controller.  If you click the show link on an account it will call this action.  Now the instance variable in the view show.html.erb will hold a single account instead of an array     
  end

  def new
    @account = Account.new                       # This initializes a new account with all the fields set to blank unless you specified a default in your migration.  This account has not been save to the db yet.  It is ready for a user to fill in.
    respond_to do |format|                       # Rails can automatically respond differently to different client request.  If a client i.e browser wants HTML rails responds with HTML.  If a client e.g. an API want XML Rails responds with XML.
      format.html # new.html.erb                 # 
      format.xml  { render :xml => @account }
    end
  end

  def edit
    @account = Account.find(params[:id])         # Same as show, but mapped to a different view
  end

  def create                                     # Finally we have a POST.  All the prior actions were GETs, but now we are saving some data to the db.
    @account = Account.new(params[:account])     # The :account key is special.  It is a hash of hashes. It is populated by the form fields in new.html.erb.  To access a specific field such as address we say <params[:account][:address]> and whatever the user entered in the address field in the View is at out fingers in the Controller. 

    respond_to do |format|
      if @account.save                           # If the validations pass and the account gets saved redirect to the show page of the new record, otherwise refresh/render the new page (hopefully showing what error caused the record to fail to save).
        format.html { redirect_to(@account, :notice => 'Account was successfully created.') }
        format.xml  { render :xml => @account, :status => :created, :location => @account }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @account.errors, :status => :unprocessable_entity }
      end
    end
  end

  def update                                     # This is another of the seven RESTful Rails actions and results in a PUT request because you are updating an existing record 
    @account = Account.find(params[:id])

    respond_to do |format|
      if @account.update_attributes(params[:account])
        format.js                                # Rails can also respond with JavaScript.  Look up UJS. Rails 3 has made large improvements here. 
        format.html { redirect_to(@account, :notice => 'Account was successfully updated.') }
        format.xml  { head :ok }
      else
        format.js
        format.html { render :action => "edit" }
        format.xml  { render :xml => @account.errors, :status => :unprocessable_entity }
      end
    end
  end

  def destroy                                    # This results in a DELETE 
    @account = Account.find(params[:id])
    @account.destroy                             # destroy is a more thourough delete and will check the options of this records associations and destroy the associated objects as well if they are dependant on this object.  The option <:dependant => :destroy> is not set for this object's only association: User.  The user this account belongs to will therefore survive the destruction of this account.

    respond_to do |format|
      format.html { redirect_to(accounts_url) }
      format.xml  { head :ok }
    end
  end
end 

看法

希望你能从这里得出你自己的逻辑。该 View 旨在呈现作为实例变量从 Controller 传递到客户端的信息:浏览器、api、智能手机。以及通过 params 散列将信息从客户端传递到 Controller 。即使带有 erb 的 View 能够执行任何 ruby​​ 代码,也不应该在 View 中执行复杂的逻辑。

如果示例 View 也有帮助,我很乐意提供帮助。

关于ruby-on-rails - 详细说明 MVC 如何在 Rails 中工作,以及 Controller 如何与表单等通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4674668/

相关文章:

ruby-on-rails - 初始化的 Mongoid 重载

ruby-on-rails - 使用 Rails 国际化静态页面

ruby-on-rails - 使用 nginx 提供预编译 Assets

javascript - 基于 jQuery PubSub 的 MVC 不会触发自定义事件

java - 使用 MVC 风格,调用查询函数的最佳位置在哪里?

ruby-on-rails - 如何将 Rails Active Records 对象转换为键 :name JSON pair

ruby-on-rails - spork 0.9.2 和 rspec 3.0.0 = 未初始化常量 RSpec::Core::CommandLine (NameError)

javascript - 在 Rails 中使用 ajax、jquery 在同一位置提交编辑后的评论

ruby-on-rails-3 - Rails3中的Ajax回调

c# - 在 MVC 应用程序中使用定时器