Why my code takes me to different URL? - ruby-on-rails

First of all, My resource is nested using to_param for slug at Community model.
I'm at example.com/shop/walmart/topic/14/edit .
If I press update without captcha input, it obviously should take me back to edit page again with flash error message.
However it takes me to example.com/shop/14/topic/14/edit . <= it's taking the same parameter. it should take 'walmart' which is community_name for first argument, and :id for topic.
All the fields are set the same with what I typed in at the previous page.
How can I avoid this? it should redirect to the same url as previous page.
routes.rb
resources :communities, :path => "shops", do
resources :community_topics, :path => "topics"
end
controller
def simple_captcha_check
if !simple_captcha_valid?
flash[:error] = 'Wrong Captcha!'
if request.put? # We came from an edit request
#community_topic = CommunityTopic.find(params[:id])
#community_topic.attributes = params[:community_topic]
render :action => :edit
elsif request.post? # We came from a new request
#community_topic = CommunityTopic.new params[:community_topic]
render :action => :new
end
end
end
models/community.rb Note that I use slug here
def to_param
"#{community_name}"
end
views/community_topics/_form.html.erb
<%= form_for #community_topic, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :body, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :body, :class => 'text_area' %>
</div>
</div>
<div class="control-group">
<div class="controls">
<%= show_simple_captcha(:label => "human authentication") %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
community_topic_index_path, :class => 'btn' %>
</div>
<% end %>
rake routes | grep community_topic
community_community_topics GET /shops/:community_id/topics(.:format) community_topics#index
POST /shops/:community_id/topics(.:format) community_topics#create
new_community_community_topic GET /shops/:community_id/topics/new(.:format) community_topics#new
edit_community_community_topic GET /shops/:community_id/topics/:id/edit(.:format) community_topics#edit
community_community_topic GET /shops/:community_id/topics/:id(.:format) community_topics#show
PUT /shops/:community_id/topics/:id(.:format) community_topics#update
DELETE /shops/:community_id/topics/:id(.:format) community_topics#destroy
By the way, my index action in controller is just like this, and it's working fine!
community_topics_controller.rb #index
def index
#community = Community.find_by_community_name(params[:community_id])
#community_topics = #community.community_topics
respond_to do |format|
format.html # index.html.erb
format.json { render json: #community_topics }
end
end

I don't see your controller actions, and don't know names of variables, but anyway in case of nested routes you have to define all urls precisely with named routes, or with polymorphic helper (as i do).
So your form helper must be looking as next:
<%= form_for([#community, #community_topic], :html => { :class => 'form-horizontal' }) do |f| %>
it have to send request to /shop/walmart/topic/14/update (or 'new' if #community_topic is a new record)
community.rb:
you can just
def to_param
community_name
end
routes.rb:
resources :communities, :path => "shop", do
resources :community_topics, :path => "topic"#, :as => :'topic' *
end
# * named route 'community_topic' can conflict with 'community_topics' of standalone route for CommunityTopic. Let it be by default: 'community_community_topic'.

Related

Rails - Submit form to controller action

I have ProjectsController and i added there a method called search_for_members i want this method to update a div with members names when the user hit submit via ajax the problem here is that i'm getting routing error
No route matches [POST] "/projects/47"
Any help?
routes.rb
resources :projects do
resources :user_stories
get '/projects/:project_id/searchformembers' => 'projects#searchformembers'
end
views/projects/show
<%= form_tag :url => {:action => "search_for_members"} , :method => 'get', :remote => true do%>
<div>
<%= text_field_tag :search, params[:search], :class => 'form-control', :placeholder => 'User name'%>
</div>
<%= submit_tag "Add user", :name => nil, :class => "btn btn-info"%>
<% end%>
<div id="members">
<%= render #users %>
<% end %>
projects_controller
def search_for_members
if (params[:search])
#users = User.search(params[:search], #project).page(params[:page]).per_page(4)
else
#users = #project.users
end
respond_to do |format|
format.js
end
end
Your route definition is wrong and does not match to your controller or form_for usage. Change your route like this:
resources :projects do
get :search_for_members, :on => :member
end
And then update your form_for definition in your view like this:
<%= form_tag search_for_members_project_path(#project), :method => 'get', :remote => true do%>
And you should be all set.

Ajax not rendering the partial in rails application

Ajax partial is not rendering in my rails application.
I am having an Article model. I am trying to add new articles using Ajax
Please find the code below.
cart.html.erb
<div id="articles">
<%= render 'showarticles' %>
</div>
cart.js.erb
$('#articles').html('<%= escape_javascript(render('static_pages/showarticles')) %>');
$('.form-control').val('')
routes.rb
match 'cart/:id', to: 'static_pages#cart', via: [:get, :post]
_showarticles.html.erb
<%= form_for #article, :remote => true do |f| %>
<%= f.text_area :name, :class => "form-control" %>
<% end %>
<% #art.each do |a| %>
<%= a.name %>
<% end %>
static_pages_controller.rb
def cart
#art = Article.all
#article = Article.new
respond_to do |format|
format.html
format.js
end
end
Thanks!
I was able to fix the issue by adding this line to my routes.rb file:
match 'cart', to: 'static_pages#cart', via: [:get, :post]
Ok,
so this
<%= form_for #article, :remote => true do |f| %>
<%= f.text_area :name, :class => "form-control" %>
<% end %>
<% #art.each do |a| %>
<%= a.name %>
<% end %>
Will go to the articles create method. Which is why your cart.js.erb isn't called. Either set the url <%= form_for #article, :url => url_for(:controller => 'static_pages, :action => 'cart', :id => #cart.id), :remote => true do |f| %> or preferably handle it in the create action of your articles controller

Why it won't detect that the request is come from edit page?

At the edit page, if I leave captcha empty, and press "save button", it takes me to #new page and says 'Wrong Captcha!'.
In fact, it should take me to edit page again.
Why my controller won't detect that the request was come from edit page?
comunity_topics_controller.rb
before_filter :simple_captcha_check, :only => [:update, :create]
def simple_captcha_check
if !simple_captcha_valid?
flash[:error] = 'Wrong Captcha!'
if request.put? # We came from an edit request
#community_topic = CommunityTopic.find(params[:id])
#community_topic.attributes = params[:community_topic]
render :action => :edit
elsif request.post? # We came from a new request
#community_topic = CommunityTopic.new params[:community_topic]
render :action => :new
end
end
end
_form.html.erb
<%= form_for :community_topic, url: community_topic_index_url, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :body, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :body, :class => 'text_area' %>
</div>
</div>
<div class="control-group">
<div class="controls">
<%= show_simple_captcha(:label => "human authentication") %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
community_topic_index_path, :class => 'btn' %>
</div>
<% end %>
UPDATE:
routes.rb
resources :communities, :path => "shop", do
resources :community_topics, :path => "topic", :as => :'topic'
end
New Update:
rake routes | grep community_topic
community_topic_index GET /shop/:community_id/topic(.:format) community_topics#index
POST /shop/:community_id/topic(.:format) community_topics#create
new_community_topic GET /shop/:community_id/topic/new(.:format) community_topics#new
edit_community_topic GET /shop/:community_id/topic/:id/edit(.:format) community_topics#edit
community_topic GET /shop/:community_id/topic/:id(.:format) community_topics#show
PUT /shop/:community_id/topic/:id(.:format) community_topics#update
DELETE /shop/:community_id/topic/:id(.:format) community_topics#destroy
Because the request method is post and not put. To use a put request you should write:
<%= form_for #community_topic, url: community_topics_url,
#MKK <%= form_for :community_topic, url: community_topic_url(#community_topic), :html => { :class => 'form-horizontal' } do |f| %> but check it within your rake routes

Self Joining ActiveRecord, Parent_Post_ID and me

So I have a self-joining model defined. Basically a post on a forum, and a parent_post that it belongs to.
class Post < ActiveRecord::Base
has_many :replies, :class_name => "Post"
belongs_to :thread, :class_name => "Post", :foreign_key => "parent_post_id"
end
Which seems fundamentally sound. I created a new RESTful route for the reply action, and an action and view.
Routes:
resources :forums do
resources :posts do
member do
get 'reply'
end
end
end
The view layer and the control action seems to be where I'm getting hosed up.
def reply
#forum = Forum.find(params[:forum_id])
#post = #forum.posts.build
#post.thread = #forum.posts.find(params[:id])
#post.title = "RE: #{#post.thread.title}"
end
def create
#forum = Forum.find(params[:forum_id])
#post = #forum.posts.build(params[:post])
#post.user = current_user
if #post.save
redirect_to forum_post_path(#forum, #post), notice: 'Post was successfully created.'
else
render action: "new"
end
end
And in the view layer I was just trying to use the same scaffold generated form partial I'm using for the standard new and edit actions.
#reply.html.erb
<%= render :partial => 'form' %>
#_form.html.erb
<%= form_for [#forum,#post], :html => { :class => 'form-horizontal' } do |f| %>
<fieldset>
<legend><h1>New Thread</h1></legend>
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field span9' %>
</div>
</div>
<div class="control-group">
<%= f.label :body, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :body, :class => 'text_area span9' %>
</div>
</div>
<div class="form-actions">
<%= f.submit 'Submit', :class => 'btn btn-primary' %>
<%= link_to 'Cancel', forum_posts_path(#forum), :class => 'btn' %>
</div>
</fieldset>
<% end %>
However, the parent_post_id is getting lost when I'm creating the post and it's getting set to nil. Do I need to create another action? Is there some other way to set the thread? Some third thing?
This will work:
Reply action:
#forum = Forum.find(params[:forum_id])
#post = #forum.posts.build
#post.thread = #forum.posts.find(params[:id])
#post.title = "RE: #{#post.thread.title}"
Then add this to your view
<%= f.hidden_field :parent_post_id, #post.thread.id %>
BTW I question whether you need a custom reply method as opposed to using built-in RESTful methods but this should fix your problem and that wasn't really your question.
add
<%= hidden_field_tag :forum_id , #forum.id %>
to your form
So basically, when you're submitting to the Posts#create action you're submitting a url that looks something like this /forum/1/posts which removes the parent_post_id from the url. Since you're using that parent_post_id to build that url, you need a way to POST with it.
My suggestion is allowing a POST to a reply resource that is nested in the posts resource.
(ie POST /forums/1/posts/1/reply)
So maybe something like this
resources :forums do
resources :posts do
# :show is actually just pointing to a form
resource :reply, :only => [:show, :create],
:controller => 'reply' #otherwise gets routed to 'replies'
end
end
So you would also need a ReplyController but that would basically match your reply method on your post controller with a few changes.
def show
#forum = Forum.find(params[:forum_id])
#post = #forum.posts.find(params[:post_id])
#reply = #forum.posts.build
#reply.thread = #post
#reply.title = "RE: #{#post.thread.title}"
end
def create
#forum = Forum.find(params[:forum_id])
#post = #forum.posts.find(params[:post_id])
#reply = #forum.posts.build(params[:reply])
#reply.thread = #post
#reply.user = current_user
if #reply.save
redirect_to forum_post_path(#forum, #post), notice: 'Reply was successfully created.'
else
render action: "show"
end
end
The biggest problem would be that you would have to abstract your Post fields from your form for block. That's because the url you're trying to POST to is going to be different. But it shouldn't be too bad just doing something like this:
reply/show.html.erb
<%=
form_for #reply, :url => forum_post_reply_path(#forum, #post),
:html => { :class => 'form-horizontal' } do |builder|
%>
<fieldset>
<legend><h1>New Reply</h1></legend>
<%= render "posts/post_fields", :f => builder %>
<div class="form-actions">
<%= builder.submit 'Submit', :class => 'btn btn-primary' %>
<%= link_to 'Cancel', forum_post_path([#forum, #post]), :class => 'btn' %>
</div>
</fieldset>
<% end %>
posts/_form.html.erb
<%= form_for [#forum,#post], :html => { :class => 'form-horizontal' } do |builder| %>
<fieldset>
<legend><h1>New Thread</h1></legend>
<%= render "post_fields", :f => builder %>
<div class="form-actions">
<%= builder.submit 'Submit', :class => 'btn btn-primary' %>
<%= link_to 'Cancel', forum_posts_path(#forum), :class => 'btn' %>
</div>
</fieldset>
<% end %>
posts/_post_fields.html.erb
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field span9' %>
</div>
</div>
<div class="control-group">
<%= f.label :body, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :body, :class => 'text_area span9' %>
</div>
</div>
Note: There's probably a better way to declare the routes than I have, but I don't really know.

Rails form issuing GET request instead of POST request

I am making a Rails 3.1 app and have a signup form that was working fine, but I seemed to have changed something to break it.. I'm using Twitter bootstrap and twitter_bootstrap_form_for gem. I made some change that messed with the formatting of the form fields, but more importantly, when I submit the Sign Up form to create a new User, the information is showing up in the URL and looks like this:
EDIT: This is happening in the latest versions of Chrome and Firefox
http://localhost:3000/?utf8=%E2%9C%93&authenticity_token=UaKG5Y8fuPul2Klx7e2LtdPLTRepBxDM3Zdy8S%2F52W4%3D&user%5Bemail%5D=kevinc%40example.com&user%5Bpassword%5D=testing&user%5Bpassword_confirmation%5D=testing&commit=Sign+Up
Here is the code for the form:
<div class="span7">
<h3 class="center" id="more">Sign Up Now!</h3>
<%= twitter_bootstrap_form_for #user do |user| %>
<%= user.email_field :email, :placeholder => 'me#example.com' %>
<%= user.password_field :password %>
<%= user.password_field :password_confirmation, 'Confirm Password' %>
<%= user.actions do %>
<%= user.submit 'Sign Up' %>
<% end %>
<% end %>
</div>
Here is the code for the UsersController:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to about_path, :notice => "Signed up!"
else
render 'new'
end
end
end
Not sure if there is more you need but if so let me know! Thank you!
Edit: For debugging I tried specifying :post and also using a plain form_for
<%= form_for(#user, :method => :post) do |f| %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Sign Up" %></div>
<% end %>
This gives me the same problem as above.
Adding routes.rb:
Auth31::Application.routes.draw do
get "home" => "pages#home"
get "about" => "pages#about"
get "contact" => "pages#contact"
get "help" => "pages#help"
get "login" => "sessions#new", :as => "login"
get "logout" => "sessions#destroy", :as => "logout"
get "signup" => "users#new", :as => "signup"
root :to => "pages#home"
resources :pages
resources :users
resources :sessions
resources :password_resets
end
The problem was that I was specifying the HTML form tag when Rails form_for generates its own. See below to add a class to a form:
<%= form_for(#user, :html => { :class => "form-stacked"} ) do |f| %>
This worked fine. I'm still not sure why having 2 tags would generate a GET request.
It looks like your for is sending a GET request, rather that a POST request. I'm not sure why this is happening (have you tried using plain form_for for debugging purposes?), but you should be able to fix it my explicitly setting the method:
<%= twitter_bootstrap_form_for(#user, :method => :post) do |user| %>

Resources