2

Still can't get this working after trying several things noted in the initial comments - I've revised below to reflect those efforts / clarify a few things.

Problem summary: I cannot create a new Post (an answer) where the parent_id of that Post equals the id of the Post for the associated question. The user starts on the posts#show page for the question Post, and clicks "Answer". I'd have thought the code below would pass the id of the question Post to the answer Posts' parent_id. But it does not. It returns parent_id = nil

I have a Posts model. A Post has a post_type_id of 1 (question) or 2 (answer).

All Posts where post_type_id = 2 have a parent_id that points to the id of the question being answered.

On posts#show I have:

<% case post_type %> 
  <% when 1 %>
<%= link_to 'Answer', new_post_path(:parent_id => @post.id) %>
  <% else %>
<% end %>

When I click on that it takes me to the new_post page and the url is: //localhost:3000/posts/new?parent_id=6

(The question in this example has id = 6, so I think that looks correct.)

In my Posts Controller I have:

  def new
    @post = Post.new
  end

  def show
  end

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    @post.parent_id = params[:parent_id]

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
    end

  def post_params
    params.require(:post).permit(:user_id, :post_type_id, :title, :content, :accepted_answer_id, :parent_id, :score, :answer_count, :favorite_count)
  end

My routes are:

          posts GET    /posts(.:format)                   posts#index
                POST   /posts(.:format)                   posts#create
       new_post GET    /posts/new(.:format)               posts#new
      edit_post GET    /posts/:id/edit(.:format)          posts#edit
           post GET    /posts/:id(.:format)               posts#show
                PATCH  /posts/:id(.:format)               posts#update
                PUT    /posts/:id(.:format)               posts#update
                DELETE /posts/:id(.:format)               posts#destroy

In new.html.erb I have:

<h3>New Post</h3>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>

And _form.html.erb is:

<%= simple_form_for(@post) do |f| %>
<%= f.error_notification %>

<div class="form-inputs">
<%- f.association :user %>
<%= f.input :post_type_id, collection: post_types, label: 'What do you want to do?' %>
<%= f.input :title %>
<%= f.input :content %>
<%- f.input :accepted_answer_id %>
<%- f.input :parent_id %>
<%- f.input :score %>
<%- f.input :answer_count %>
<%- f.input :favorite_count %>
</div>

<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>

I'd really appreciate any suggestions on how I can get this working.

Thanks!

WallE
  • 83
  • 1
  • 1
  • 9
  • Please post your routes file. – Arslan Ali Jun 23 '15 at 14:46
  • It only sets parent_id if `@post.post_type_id == 2`. is this being set to 2 somewhere else? – Max Williams Jun 23 '15 at 14:46
  • Also post your `show` method in controller. – Arslan Ali Jun 23 '15 at 14:48
  • 2
    Does your form in `new.html.erb` have the `parent_id` anywhere? Even a hidden value? – sjagr Jun 23 '15 at 14:49
  • the @post.post_type_id is working correctly -- I'm currently doing this in a choice box. Rails console shows that that part is working. – WallE Jun 23 '15 at 14:49
  • can you show us the new.html.erb – khaled_gomaa Jun 23 '15 at 14:51
  • Sure, but without logic in your `create` method to set `parent_id` again from either a form variable, or from your choice logic, then there's no saved state of the `@post` from `new` to `create`. The real problem lies in the contents of your `new.html.erb` and `create` method. – sjagr Jun 23 '15 at 14:51
  • Is there a field in the form for the parent_id? Because it will create a completely new post object in the create method only using the data passed as parameters (usually form data) in the POST request. – irruputuncu Jun 23 '15 at 14:51
  • 1
    `link_to 'Answer'....` lies in posts#show as you said in your question, and your `show` method is empty. How are you getting `@post`? – Arslan Ali Jun 23 '15 at 14:55
  • `create` and the form looks good. I second @ArslanAli's point. – sjagr Jun 23 '15 at 14:57
  • Sorry, I'm confused: should I delete <%- f.input :parent_id %> from my form? (To sjagr's point.) Do I need to repeat the setting of :parent_id in create? I just tried those two things and it still doesn't work. – WallE Jun 23 '15 at 14:59
  • @post refers to the current post I'm on in posts#show. So in this post Post.id = 6. Arslan, maybe I'm not understanding your question. Please let me know. – WallE Jun 23 '15 at 15:04
  • Yes but `def show` should have some sort of `@show = Product.find(params[:post])` – sjagr Jun 23 '15 at 15:21
  • Please paste your `post_params` method. If that has a `permit`, does the whitelist include `parent_id`? – Kristján Jun 23 '15 at 15:30
  • Did you mean Post.find(params[:post]) ? (I don't have a Product model) I tried this & I'm getting an error "Couldn't find Post with 'id'=": def show @show = Post.find(params[:post]) end – WallE Jun 23 '15 at 15:31
  • Kristjan, just added it - it does include parent_id – WallE Jun 23 '15 at 15:33
  • If you only have 2 post types (either Q or A), I suggest you add a convenient method in your class `def question?{ post_type == 1 }`, so then you don't have to bother with meaningless `case when` and you can write `<%if @post.question? %> ... <% else %>` – Cyril Duchon-Doris Jun 23 '15 at 16:17
  • Thanks, I actually have 4 post types, just truncating b/c they're not relevant to this question. – WallE Jun 23 '15 at 16:18
  • We don't know what the problem is/ what you're trying to do (anymore ? did you edit the question and removed the description of your problem ?) – Cyril Duchon-Doris Jun 23 '15 at 16:22
  • That is what happened, thanks. I accidentally deleted more than I intended when editing. I've added a problem summary at the top now. – WallE Jun 23 '15 at 16:27

1 Answers1

2

Okay, so your user clicks on answer, it then forwards the question ID as a ROOT param (params[:parent_id])

Now, you want to tell your new action that the post you're building is an answer to a question, so this is where you should use the param

controllers/posts_controller.rb

def new
  @post = Post.new
  @post.parent_id = params[:parent_id] if params[:parent_id]

Then in your form, you can add a hidden field (User don't care about the id). I believe if the field .parent_id wasn't set, it will leave a blank value and it's fine

views/posts/_form.html.erb

<%= f.hidden_field :parent_id %>

Then when you POST your new answer, the :parent_id will be sent and you don't need to worry about it

controllers/posts_controller.rb

def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    # No need for the below line, :parent_id is already in post_params
    # @post.parent_id = params[:parent_id]

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  def post_params
    params.require(:post).permit(..., :parent_id, ...)
  end

EDIT : Answers to your questions in comments

Why does @post.parent_id = params[:parent_id] belongs to #new

With this line, you actually set the :parent_id memory variable of the "template @post object" you are preparing for the #new action. Now when you render the view, by default every form helper will LOAD the values in memory if they exist. When you're doing f.input :content, the form_builder will generate the HTML tags, but also look in the memory for @post.content. Because the model was generated blank, there is no value so it will show an empty field. So when you're calling f.hidden_field :parent_id, it will actually find the variable (thanks to the code we just added) and use it.

<%- instead of <%=

I personally never use <%-, and I had to google it, and found this question. <%- will just avoid line breaks, so it would work as well

Why a hidden field ?

It's just a matter of user experience. A hidden field will write in the HTML, but will hide it to the user. The user doesn't give a damn shit about your :parent_id. You are using ActiveRecord, so IDs look very nice, but if you try other databases system, your ID might look like 0bef0600008de. And your user definitely doesn't care that he's adding an answer to a question 0bef0600008de.

However h might be interested in this :

_form.html.erb

<% if @post.parent_id %> <!-- if variable parent_id exists <=> we are writing an answer -->
  <h2>You are writing an answer for the question <%= Post.find(@post.parent_id).title %></h2>
<% end %>
Community
  • 1
  • 1
Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
  • An alternative syntax to `f.hidden_field` can be `f.input :parent_id, as: :hidden` – Cyril Duchon-Doris Jun 23 '15 at 16:42
  • Thanks for posting a potential solution! Unfortunately I'm still getting parent_id = nil Are you currently able to get it to work? I'm wondering where else in my app I could be going wrong.... – WallE Jun 23 '15 at 16:46
  • Ok, I know that `f.hidden_field` method is annoying, and doesn't work as expected. Try `f.hidden_field :parent_id, value: (params[:parent_id] if params[:parent_id])`. – Cyril Duchon-Doris Jun 23 '15 at 16:48
  • Ok, this totally worked! Yay! I had tried explicitly stating the controller and didn't undo that before trying your solution, and that had thrown it off, my apologies. But once I realized my error, it worked great! Thank you so much! Why does the setting of :parent_id belong in new & not create? And is a hidden_field always required, rather than leaving it out with <%- %> like I had done initially? – WallE Jun 23 '15 at 16:59
  • Sorry, our comments were simultaneous. I believe your original solution works. I'd just made a change that was throwing it off. Thank you again! – WallE Jun 23 '15 at 17:00
  • Edited post to answer your questions – Cyril Duchon-Doris Jun 23 '15 at 17:31