Rails: Creating new posts in the other model's show action

There are several locations and people can write posts about those locations. So what I did until now is that I created a table locations (rails generate scaffold locations name:string) and a table posts (rails generate scaffold posts title:string text:string author:string image:string location_id:integer). So the Table posts has a foreign key to the table locations. So it's possible to view the posts in the show action of the table.

View for /locations/1 (show action of the location model) and View for /posts/new:

What i want is that someone visiting one specific location can create a post without the need to fill the id-box as you can see below. It should automatically know that this post belongs to location with the current id. What do I have to change in the controller and what do I have to do in the html.erb-files so it works? I already tried this... but it retrieves a noMethod Error.

  def newpost
    @post = current_location.posts.build 

    respond_to do |format|
      format.html 
      format.json { render json: @locations }
    end
  end 

So I followed Charles' and Zajn's instructions.

class PostsController < ApplicationController
(...)
  def new
    #@post = Post.new
    @post = @location.posts.build

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @post }
    end
  end
(...)
end

in config/routes.rb

resources :locations do
  resources :posts
end

the posts-partial

<%= form_for @post do |f| %>
  <%= f.label :title, 'Title' %>
  <%= f.text_field :title %>

  <%= f.label :title, 'Text' %>
  <%= f.text_field :text%>

  <%= f.label :title, 'Author' %>
  <%= f.text_field :author %>

  <%= f.hidden_field :location_id %>
  <%= f.submit "Submit" %>
<% end %>

and there still seems to be an error:

NoMethodError in PostsController#new

details:

undefined method `posts' for nil:NilClass
app/controllers/posts_controller.rb:28:in `new'

Request
Parameters:
{"location_id"=>"1"}

Response
Headers:
None

second try: Now I edited the PostsController

  def new
    #@post = Post.new
    @location = Location.find(params[:location_id]) # You can move this to a before_filter, if you prefer
    @post = @location.posts.build

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @post }
    end
  end

and it seems like there's no error in the controller anymore. Now there's some NoMethodErrorin the html.erb-files:

undefined method 'posts_path' for #<#<Class:0x2404384>:0x204ed98>

1: <%= form_for @post do |f| %>
2:     <%= f.label :title, 'Title' %>
3:     <%= f.text_field :title %>
4: 

app/views/posts/_form.html.erb:1:in `_app_views_posts__form_html_erb___1061496502_7409780'
app/views/posts/new.html.erb:3:in `_app_views_posts_new_html_erb__238125222_5750540'
app/controllers/posts_controller.rb:31:in `new'

my _form.html.erb:

<%= form_for @post do |f| %>
    <%= f.label :title, 'Title' %>
    <%= f.text_field :title %>

    <%= f.label :title, 'Text' %>
    <%= f.text_field :text%>

    <%= f.label :title, 'Author' %>
    <%= f.text_field :author %>

    <%= f.hidden_field :location_id, :value => @location.id %>
    <%= f.submit "Submit" %>
<% end %>

my new.html.erb

<h1>New post</h1>

<%= render 'form' %>

<%= link_to 'Back', posts_path %>

I already tried to simply delete the last code <%= link_to 'Back', posts_path %>and it still retrieves the error, even I saved everything, shut down the server and reopened it. But I think the problem is not the posts_path. Because if I change the <%= form_for @post do |f| %>in the html.erb file into <%= form_for @location.post do |f| %>, it retrieves a NoMethodError for 'post'

Answers


It sounds like you want posts to be a nested resource under locations.

If that's what you're trying to do, then in config/routes.rb, you should have:

resources :locations do
  resources :posts
end

The url to create a new post for the location with id = 1 is /locations/1/posts/new, and your new action in PostsController should look like this:

def new
  @location = Location.find(params[:location_id]) # You can move this to a before_filter, if you prefer
  @post = @location.posts.build

  respond_to do |format|
    format.html
    format.json { render json: @post }
  end
end

Your app/views/posts/_form.html.erb partial should look like this:

<%= form_for [@location, @post] do |f| %>
  <%= f.label :title, 'Title' %>
  <%= f.text_field :title %>

  <%= f.label :title, 'Text' %>
  <%= f.text_field :text%>

  <%= f.label :title, 'Author' %>
  <%= f.text_field :author %>

  <%= f.hidden_field :location_id %>
  <%= f.submit "Submit" %>
<% end %>

Note that, with nested resources, the route helpers that you use in your views are different. For example, to get the path to the index action for the Posts belonging to a given location, you would use location_posts_path(@location), rather than posts_path.


You could simply add a hidden field that contains the id of the location to the form where you are creating the post.

So, something like this:

<%= form_for @post do |f| %>
    <%= f.label :title, 'Title' %>
    <%= f.text_field :title %>

    <%= f.label :title, 'Text' %>
    <%= f.text_field :text%>

    <%= f.label :title, 'Author' %>
    <%= f.text_field :author %>

    <%= f.hidden_field :location_id, :value => @location.id %>
    <%= f.submit "Submit" %>
<% end %>

Where @location is an instance variable containing the current location that you're viewing.


Need Your Help

Why do the environment variables set in command prompt have no effect when I start Spyder

python environment-variables spyder theano

I am using the Spyder Anaconda IDE for Python. I am writing a code in the Spyder IDE that requires few environment variables to be set ($CPATH, $LIBRARY_PATH and $LD_LIBRARY_PATH) for the Theano li...

ONVIF and PTZ Access to IP Cameras

web-services soap onvif

I'm in trouble here about the ONVIF IP Camera specification. I've built a program that is able to use the standard to contact cameras and send them standard media/device requests.