【问题标题】:Creating a new object in form_for for Ajaxified form in Rails 4在form_for中为Rails 4中的Ajaxified表单创建一个新对象
【发布时间】:2014-01-23 23:16:54
【问题描述】:

使用 Rails 4,制作一个简单的单页应用程序。

我的根目录设置为显示一系列非常短的帖子的索引页。另一方面,我有一个部分表单,因此有人可以轻松提交新帖子。

我决定对表单提交进行 Ajaxify 处理,以便在不重新加载页面的情况下将新帖子附加到列表顶部并清除表单。

关于我的表单的一个注释 - 每个帖子都属于一家公司,因此我在表单内有 <%= fields_for Company.new do |company|... %>。在创建动作中,我在公司上调用first_or_create,因此如果公司不存在,则在提交时创建并与新帖子相关。

最终,我不得不在我的表单中显式地创建新对象,而不是将本地变量传递给我的局部变量并在表单中使用裸词。我试图理解为什么会这样,以及我最终如何能够实施一种更被接受的方法。

在下面实现我的最终解决方案之前,我试图让它像这样工作:在帖子控制器的索引操作中,不仅声明@post = Post.new@company = Company.new,而且还声明@new_company = Company.new@new_post = Post.new .然后在我的 create.js.erb 文件中,当重新呈现表单时,将 @new_company@new_form 作为本地人(如 $(".js-ref-form").html("<%= escape_javascript(render partial: 'form', locals: { post: @new_post, company: @new_company ) %>");)传递,然后在表单中使用裸词 <%= form_for post .... %>。这似乎是更标准的方式,但我无法让它工作,直到我放弃实例变量和局部变量,并在表单中明确创建新对象。

posts_controller.rb:

class PostsController < ApplicationController

  respond_to :html, :js

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

  def create
    @company = Company.where(name: post_params[:company]).first_or_create
    @post = @company.posts.build(company_id: @company.id, details: post_params[:details], link: post_params[:link],
                                         expiration: post_params[:expiration], code: post_params[:code], limit: post_params[:limit])
    if @post.save
      flash[:success] = "Post submitted!"
    else
      flash[:danger] = "Problem submitting post. Please try again."
    end

    respond_with(@post) do |f|
      f.html { redirect_to root_path }
    end
  end

views/posts/create.js.erb:

<% if @post.valid? %>
  $(".js-post").prepend("<%= escape_javascript(render(@post)) %>");
  $(".js-post-form").html("<%= escape_javascript(render partial: 'form') %>");
<% else %>
  $(".js-post-form").replaceWith("<%= escape_javascript(render partial: 'form') %>");
<% end %>

views/posts/_form.html.erb

# writing form_for @post doesn't work with this solution, and if I pass
# in locals to the partials, i.e. render partial: 'form', locals: { post: @post }
# and using form_for post didn't work either
<%= form_for Post.new, html: { class: 'form-horizontal' }, remote: true do |f| %>
  <h2>Add Post</h2>
  <%= render 'shared/error_messages' %>

  <%= f.label :company, "Company" %>
  # Same problem as the comment above
  <%= fields_for Company.new do |company| %>
      <%= f.text_field :company, class: 'form-control' %>
  <% end %>

  <br>

  <%= f.label :details, "What's new?" %> <span class="detail-counter pull-right"></span>
  <%= f.text_area :details, class: 'form-control' %>

  <br>

  <%= f.submit "Submit", class: 'btn btn-lg btn-block btn-primary' %>
<% end %>

<script type="text/javascript">
  var elem = $(".detail-counter");
  $("#post_details").limiter(140, elem);
</script>

视图/帖子/index.html.erb:

<div class="row">
  <div class="col-md-4 post-form">
    <div class="js-post-form">
      <%= render partial: 'form' %>
    </div>
  </div>
  <div class="col-md-8">
    <div class="post-list js-posts">
      <% if @posts.any? %>
        <%= render @posts %>
      <% else %>
        No posts yet!
      <% end %>
    </div>
  </div>
</div>

routes.rb

CompanyPosts::Application.routes.draw do
  resources :posts

  root to: 'posts#index'
end

型号:

post.rb

class Post < ActiveRecord::Base
  default_scope -> { order('created_at DESC') }
  validates :details, presence: true, length: { maximum: 140 }

  belongs_to :company

公司.rb

class Company < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

【问题讨论】:

  • 我可以看看你的routes.rb吗?
  • 当然,我会在上面添加它
  • 在模型中,您有 Company has_many :postsPost belongs_to :company?
  • 你的观点...他们在views/posts?
  • 呃……我什么都没得到。一切看起来都很标准 =/

标签: jquery ruby-on-rails ajax forms ruby-on-rails-4


【解决方案1】:

好的,想通了。为了能够将局部变量传递给我的表单部分并在表单中使用裸词,我必须在 @ 中为 new 帖子和 new 公司对象创建实例变量987654321@ 动作,而不是像我以前那样在索引动作中。

然后在我的 index.html.erb 文件中我可以做 &lt;%= render partial: 'form', locals: { post: @post, company: @company } %&gt; 和 create.js.erb:

<% if @post.valid? %>
  $(".js-posts").prepend("<%= escape_javascript(render(@post)) %>");
  $(".js-post-form").html("<%= escape_javascript(render partial: 'form', locals: { post: @new_post, company: @new_company }) %>");
<% else %>
  $(".js-post-form").html("<%= escape_javascript(render partial: 'form', locals: { post: @post, company: @company }) %>");
<% end %>

另外,我必须在我的帖子控制器中定义两个参数,因为我实际上是同时提交了两个表单。我修改了fields_for 标签,希望以更合适的方式工作:

<%= form_for post, html: { class: 'form-horizontal' }, remote: true do |f| %>
  <h2>Add Post</h2>
  <%= render 'shared/error_messages' %>

  <%= f.label company, "Company" %>
  <%= fields_for company do |company| %>
      <%= company.text_field :name, class: 'form-control' %>
  <% end %>
  # The rest of the form is the same as above...

class PostsController < ApplicationController

  respond_to :html, :js

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

  def create
    @company = Company.where(name: company_params[:name]).first_or_create
    @post = @company.posts.build(post_params)
    @new_post = Post.new
    @new_company = Company.new

    if @post.save
      flash[:success] = "Post submitted!"
    else
      flash[:danger] = "Problem submitting post. Please try again."
    end

    respond_with(@post) do |f|
      f.html { render :index }
    end
  end

  private

    def post_params
      params.require(:post).permit(:details)
    end

    def company_params
      params.require(:company).permit(:name)
    end
end

现在我不必在表单中显式创建对象。尽管仍然感谢任何进一步的改进建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多