Why aren't instance variables defined in a con

2019-09-01 03:40发布

问题:

For example, given a basic controller such as:

class PostsController < ApplicationController
  def index
    @post = Post.all
  end

The instance variable @post is available in the view posts/index.html.erb but not the partial posts/_index.html.erb

My primary questions are: Why is this? and How can I define a method for a partial in a controller to for example, pass an instance variable?

On a more specific note: I ask this because the way I am rendering data in a separate, primary view welcome/index.html.erb is via this posts partial. I have gotten around this limitation by directly calling the model with Post.all in the posts/_index.html.erb partial, but as far as I understand this ignores MVC architecture and severely limits me from developing more complex methods, unless I really break convention and write them into the view (which I assume may work but is poor design).

Currently, @post is passing a nil to the partial symbol :post in welcome/index.html.erb

Clearly I'm missing something, so any insight would be greatly appreciated!

Thank you

Relevant files:

views/
  posts/
    _index.html.erb
    _new.html.erb
    show.html.erb
  welcome/
    index.html.erb

controllers/ 
  posts_controller.rb
  welcome_controller.rb

posts/_index.html.erb

<% post.reverse.each do |post| %>
  <div class="panel panel-default">
    <div class="panel-body">
      <%= post.text %>
    </div>
  </div>
<% end %>

posts/_new.html.erb

<%= form_for :post, url: posts_path do |f| %>
  <p id="post_box">
    <%= f.text_area :text %>
  </p>

  <p>
    <%= f.submit %>
  </p>
<% end %>

posts/show.html.erb

<%= @post.text %>

welcome/index.html.erb relevant portions (partials)

<%= render partial: "posts/index", locals: {post: @post} %>
<%= render partial: "posts/new" %>

controllers/posts_controller.rb

class PostsController < ApplicationController
  def new
  end

  def create
    @post = Post.new(post_params)

    @post.save
    redirect_to '/'
  end

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

  def index
    @post = Post.all
  end

  private
    def post_params
      params.require(:post).permit(:text)
    end

end

controllers/welcome_controller.rb

class WelcomeController < ApplicationController
end

回答1:

You're right that you're breaking MVC conventions by calling controller-level object lookups in your view.

When you call the render action on the partial you have a variety of arguments to send, one of which is a locals hash that takes a variable you want to pass directly into your partial.

It looks like this:

<%= render partial: "something", locals: {posts: @posts} %>

The rails guides are a great resource on the topic. More on that here.