详细说明MVC在Rails中如何工作,以及控制器如何与表单通信等?

发布于 2024-10-11 09:48:23 字数 655 浏览 1 评论 0原文

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

我了解 MVC 的一般结构以及模型如何存储数据库结构,以及控制器如何与数据库交互并将信息传递给视图。

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

但我到底该如何在控制器的 CRUD 元素中做到这一点,为什么呢?

请使用一个简单的示例 - 例如,向用户显示其银行帐户的余额(我知道这有很多复杂性,但为了解释起见,请忽略它们)。模型会是什么样子(仅包括:名称、地址、交易类型(存款/取款)、余额)。

视图会是什么样子?控制器会是什么样子?您所做的任何选择(例如使用表格)请解释一下。为什么要使用表单,而不是下拉菜单?(通俗地说)表单或下拉菜单如何与控制器交互?如何将捕获的信息传输到数据库以及为什么要这样做?

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

提前致谢。

Perhaps this can even become a Community Wiki, but I would love a detailed description of how the controller works - or rather, how I can get it to do what I want it to do.

I understand the general structure of MVC and how the model stores the db structure, and the controller interacts with the db and passes info to the view.

However, I am puzzled (on a fundamental level) about how to accomplish simple tasks using my controller. I know that if I want to create a new record for a model/object, I just do object = Object.new(:name => "Object Name") in the Rails console.

But how on earth would I do that in the CRUD elements of the controller and why?

Please use a simple example - e.g. showing a user the balance of their bank account (I know there are many complexities surrounding this, but ignore them for the sake of this explanation). What would the model look like (just include: Name, Address, Transaction Type (Deposits/Withdrawals), Balance).

What would a view look like? What would the controller look like? Any choices you make (like using a form) please explain them. Why would you use a form, as opposed to a drop down menu and (in layman terms) how does the form or drop down menu interact with the controller? How do I get the info captured there to the db and why am I doing it that way?

I know this sounds like a lot to ask, but I have done RailsTutorial.org, watched many Railscasts, read the Rails guides, and read many other tutorials and still have some basic gaps in my understanding of the way Rails works and why.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云淡月浅 2024-10-18 09:48:23

我不知道我还能提供多少帮助,但我理解你自己刚刚走上正轨的痛苦。 ghoppe推荐的文章《瘦控制器,胖模型》讲解了Ms Vs•的功能。很好。鉴于这并不能完全回答你的问题,我将尝试解释每个结构的机制。

模型

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 帮助程序,以及您希望对象能够在整个模型视图和控制器中使用的任何其他方法或库。

控制器

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 

视图

希望您可以从这里绘制自己的逻辑。该视图旨在呈现作为实例变量从控制器传递到客户端的信息:浏览器、API、智能手机。以及通过参数哈希将信息从客户端传递到控制器。即使带有 erb 的视图能够执行任何 ruby​​ 代码,视图中也不应该执行复杂的逻辑。

如果示例视图也有帮助,我很乐意效劳。

I don't know how much more help I can be, but I understand your pain having just come to rails myself. The article recommended by ghoppe, "Skinny Controller, Fat Model" explains the function of Ms Vs & Cs nicely. Seeing as that does not fully answer your question I will try to explain the mechanics of each structure.

Model

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

The model describes your object. Like an object in any OOP language you want to put all of your object logic here. This includes the rails helpers for association(has_one, belongs_to, ...) and validation, as well as any other method or library you want the object to be able use throughout your Models Views and Controllers.

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

Hopefully you can draw your own logic from here. The view is designed to render information passed as instance vars from a controller to a client: browser, api, smart phone. As well as to pass information from a client to the controller via the params hash. No complicated logic should get performed in a view even though a view with erb has the capability to execute any ruby code.

If an example view would also be helpful I am happy to oblige.

荒岛晴空 2024-10-18 09:48:23

关于控制器的最佳描述:

http://edgeguides.rubyonrails.org/action_controller_overview.html

http://edgeguides.rubyonrails.org/routing.html

控制器不与数据库。控制器与模型对话,然后模型与数据库进行通信。

当我开始时,我发现使用脚手架并查看创建的内容非常有用。

执行此操作:

rails generate scaffold Post name:string title:string content:text

检查 app/ 文件夹下的所有文件。检查文件 config/routes

然后在此处评论您的具体问题。

The best description of what the controller is:

http://edgeguides.rubyonrails.org/action_controller_overview.html

http://edgeguides.rubyonrails.org/routing.html

The controller doesn't communicate with the Database. The controller talks to the model, which then communicate with the database.

When I was starting I found very useful to use scaffolding and just looking at what was created.

Do this:

rails generate scaffold Post name:string title:string content:text

Examine all files under the app/ folder. Examine the file config/routes

Then comment here your specific questions.

原来分手还会想你 2024-10-18 09:48:23

起初,我认为这个问题太宽泛了,类似于“我如何编程?”但读完你的评论后,我明白你的意思了。您不太了解 MVC 在 Rails 中的工作原理,并且想知道您的代码去了哪里。

你应该努力的是一个瘦的控制者和一个胖的模型。让逻辑远离观点。因此,在您的示例中,您计算​​模型中的帐户余额,并将该信息(使用控制器)传递到视图。

为了给初学者提供示例代码的简洁解释,我推荐这篇文章在这里

At first, I thought this question was far too broad, along the lines of "how do I program?" But after reading your comments, I see what you're getting at. You don't quite grasp how MVC works in Rails and are wondering where your code goes.

What you should strive for is a Skinny Controller and a Fat Model. Keep logic out of views. So in your example, you calculate the account balance in the Model, and pass that information along (using the controller) to the view.

For a concise explanation for beginners with sample code, I recommend this article over here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文