Rails: Forms_For new post calling different controller on submit - ruby-on-rails

I've been working on a social site using the Rails framework. I just finished setting up a form and was able to submit a couple subposts. It worked for a bit, but now when I submit a subpost using forms_for(#subpost), it attempts to submit a completely different form on a separate view. No clue why it would call a separate form that hasn't even been rendered but hoping someone can help.
SubPost Controller
class SubPostsController < ApplicationController
def create
#subpost = SubPost.new(sub_post_params)
if #subpost.save
Form I want to submit
<%= form_for(#subpost) do |z| %>
<%= render 'shared/error_messages', object: z.object %>
<div class="field">
<!--<input type="text" name="sub_post[user_id]" value="<%# current_user %>" style="display:none;"/>-->
<input type="text" name="sub_post[micropost_id]" value="<%= micropost_id %>" style="display:none;"/>
<%= z.text_area :content, placeholder: "What's on your mind?" %>
</div>
<%= z.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
Updated to answer question
So basically I have my users personal page which displays their feed displaying a form under each post to submit a subpost. On the actual show page, there is no partial or render for post form, but that is what gets called each time I submit to the subpost form. The controller for the users page has two variables that I use to render the posts and subposts, #post = #user.posts.build and #subpost = #post.sub_posts.build

You can do something like this:
#some_controller.rb
def some_method
#posts = Post.all
SubPost.new
end
In your form you can use url option to take form parameters to create action. Assuming your routes are nested you can do something like this:
<% #posts.each do |post| %>
<%= form_for :subpost, url: some_path(#user, post) do |z| %>
// you need to replace some_path(#user,post) by your path helper
<%= render 'shared/error_messages', object: z.object %>
<div class="field">
<%= z.hidden_field :post_id, value: post.id %>
<%= z.text_area :content, placeholder: "What's on your mind?" %>
</div>
<%= z.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>

Related

Render in a different order on the page breaks the routing

I have Challenges containing Puns, and it is possible to vote on puns. On the Challenge Show page, all puns are rendered and show their votes count. This is currently on the view page:
<%= render #challenge.puns.reverse %>
<br>
<div id="form">
<%= render "puns/form" %>
</div>
I want the puns form to appear above the items (puns) already submitted. But if swap them around, like this:
<div id="form">
<%= render "puns/form" %>
</div>
<%= render #challenge.puns.reverse %>
I get a controller error and pun.id is not suddenly not available and the voting link breaks.
No route matches {:action=>"upvote", :challenge_id=>"9", :controller=>"puns", :id=>nil}, missing required keys: [:id]
Here is the puns/form part that is causing the issue
<% if signed_in? %>
<% if current_user.voted_for? pun %>
<%= pun.votes_for.size %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% else %>
<%= link_to like_challenge_pun_path(#challenge, pun.id), method: :put do %>
<span class="heart_like">❤</span> <%= pun.votes_for.size %>
<% end %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% end %>
<% end %>
It is the like_challenge_pun_path that throws an error but I cannot understand why. I am declaring #challenge again here, so it should be able to get the id.
Here is the form for the puns:
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
<span class=".emoji-picker-container">
<%= f.text_area :pun_text, placeholder: "Add pun", data: { emojiable: true } %>
</span>
<%= f.submit %>
<% end %>
Also, here is my routes setup
resources :challenges do
resources :puns do
member do
put "like", to: "puns#upvote"
put "dislike", to: "puns#downvote"
end
end
end
and the corresponding action to upvote
def upvote
#pun = #challenge.puns.find(params[:id])
#pun.upvote_by current_user
redirect_to #challenge
end
Can anyone help?
I think the code is for the puns collection.
I assume the issue is that in the form you have something like:
#challenge.puns.build
So in #challenge.puns collection appears not persisted record (without id), so path for this model cannot be generated.
As a quick solution I suggest:
<%= render #challenge.puns.reverse.select(&:persisted?) %>
UPDATE:
As I assumed you have
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
You can also try:
<%= form_for([#challenge, Pun.new]) do |f| %>
Or solve it in the controller. But need to see controller code for it.

Using Paginate Directly after Submission

I am creating an evaluation form where a user will submit form after form by using kaminari pagination. The way I have it set up right now though is that the user will answer the questions, submit the form with an f.submit button, then once the profile updates, the user will have to manually select 'Next User' using the paginate button below the f.submit button. I would love for it to both submit the form and send the user to the next evaluation in line under one button action, not two. I have been playing around with trying to incorporate the paginate code into my f.submit button, but it keeps throwing errors. I was wondering if there was an easy way to go about this, thanks in advance!
<h2>Team Member Evaluation</h2>
<br> </br>
<% #users.each do |user| %>
<h4> <%= user.name %> </h4>
<%= form_for(user) do |f| %>
<% begin %>
<h8> Hunger for Wisdom </h8>
<div class="form-inline">
<div class="form-group">
<%= f.radio_button :current_one, 1 %>
<h7> 1 </h7>
</div>
<div class="form-group">
<%= f.radio_button :current_one, 2 %>
<h7> 2 </h7>
</div>
<% end %>
<div class="col-md-3 col-md-offset-4">
<%= f.submit "Submit Score", class: "btn btn-default" %>
<% rescue ActionController::RedirectBackError %>
</div>
</div>
<% end %>
<%= paginate #users %>
<% end %>
<% end %>
Right now it is set up to whenever the user submits the form, the rescue action will direct the user back to a refreshed page of the evaulation form they just submitted, and then they must click next where the <% paginate #users %> is to go to the next form. I would like once the f.submit button is pressed to update and then immediately take the user to the next form.
In the controller action for the submit you could just increment the page count like this:
#users = User.page params[:page].to_i + 1
This is assuming you aren't using any other scopes to get the #users collection. The kaminari github repo has more information on available methods here.
If it is on the first page then the page query var is probably nil so you would have to account for this and send it to page 2 in this special case.

Redirect after search form submit Rails 4

I've built a custom search in a navbar that submits to my index action that works great when I'm at my index view. But once i'm in a different view, the params are correctly submitted, but I need to redirect to my index view. Thus far i've been unable to figure it out. Any help would be VERY appreciated!
My search function in my model
def self.search(search_option, search_text)
where("#{search_option} like ?", "#{search_text}%")
end
controller:
def index
if params[:search_text]
#books = Book.search(params[:search_option].downcase, params[:search_text].capitalize)
else
#my_books = current_user.books
end
end
search form in view:
<%= form_tag books_path, method: :get do %>
<div class="form-group">
<% options_array = ["Genre","Category"] %>
<%= select_tag :search_option, options_for_select(options_array), class: "btn btn-default dropdown-toggle select-options" %>
<%= text_field_tag :search_text, params[:search], class: "form-control" %>
</div>
<%= submit_tag "Search", :name=>nil, class: "btn btn-default" %>
<% end %>
Real new developer mistake here, but the problem was I was putting my search form into a Bootstrap navbar, inside existing <form></form> tags. This is short circuiting my search. Deleted those and it worked just as expected!

How HTTP method works in a form_tag helper?

I tried to set up a form which I wanted it to move to members#index.
But with the code①, I failed and the form moved to members#show.
☆code①
<%= form_tag :action => 'index' do %>
<div class = "field">
<%= label_tag 'place', '活動場所:' %><br />
<%= text_field_tag 'place' %>
</div>
<%= submit_tag '検索' %>
<% end %>
And I got some advice and fixed the code②.
I have a question. Why did I have to change the method from "post" to "get"?
☆code2
<div class= "form_index">
<%= form_tag({:action=>"index"}, {:method=>"get"}) do %>
<div class="from_field_index">
<%= label_tag 'place', '場所:' %>
<%= text_field_tag 'place' %>
</div>
<div class="search_button">
<%= submit_tag '検索' %>
<% end %>
</div>
</div>
☆members_controller
def index
if params[:place].present?
#members = Member.where("place like ?" , "%" + params[:place] + "%")
else
#members = Member.all
end
respond_to do |format|
format.html # index.html.erb
format.json
end
end
GET implies to retrieve something from server. POST implies to add something to server.
Search will get some results from server, so the conventional way is to use GET on this action. Search form is the perfect example of form using GET.
Also, your controller action index responds to 'GET' only, defined by default resource route. It also need the request sent by your client side to be 'GET'.
Another benefit of using GET on search is, the params will be in url so the url is bookmarkable, shareable and history nagivatable. Think about Google, you can share a search result by just copying the link.

access a partial's form_for(#variable) from any page

I just finished Hartl's RoR tutorial and am now trying to mess around with some more stuff.
Specifically: I'm trying to allow the user to create microposts on any page, by rendering the micropost partial in the header.html.erb file (which is rendered on every page).
the partial:
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "micropost" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
Doing this has resulted in the error on line #1 of the partial: undefined method 'model_name' for NilClass:Class on any page which I have not fixed by adding #micropost = current_user.microposts.build in the controller method that links to said view. For example:
#in controllers/static_pages_controller.rb
def about
if signed_in?
#micropost = current_user.microposts.build
end
end
Would fix this error when I visit the about page
I've been trying to figure out a way to do a "blanket fix" that will work on all pages without me having to paste in the declaration everywhere, any ideas?
I think you have SessionController, is created as follow guide in Tutorial, so you can make a helper method in SessionController, example:
def post_micropost
if signed_in?
#micropost = current_user.microposts.build
end
end
Then, in your StaticsController, add a before_filter at the top of controller:
before_filter :post_micropost
So, in any action of StaticPagesController, user can post micropost also if they are signed in.
You don't need to use the form_for builder here; Rails also provides a form_tag helper for more generic forms:
<%= form_tag create_micropost_path, method: :post do %>
<%= text_area_tag :micropost_content, placeholder: "micropost" %>
<%= submit_tag "Post", class: "btn btn-large btn-primary" %>
<% end %>
This way, you don't need to build the object when loading every page, but microposts#create can still pull data from params[:micropost]. See here for more info.
You can add this before the form
<% #micropost ||= current_user.microposts.new %>

Resources