Ajax not rendering the partial in rails application - ruby-on-rails

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

Related

Rails 4 render partial for nested attributes without loop

Suppose I have a form like below
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= uni_form.fields_for :apps do |builder| %>
<%= render 'app', uni_form: builder %>
<% end %>
<% end %>
and my app partial is
<div>
<%= uni_form.label :uni_id, "University" %>
<%= uni_form.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
</div>
Now I want the first form code without the loop. Something like this
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<% end %>
How can I do this?
Firstly, don't build your associated objects in your view - do it in your controller:
#app/controllers/unis_controller.rb
class UnisConstroller < ApplicationController
def new
#uni = Uni.new
3.times do
#uni.apps.build
end
end
end
Secondly, the fields_for method is your friend here.
You'll gain what you need by using the following:
#app/views/unis/new.html.erb
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<%= uni_form.fields_for :apps do |builder| %>
<%= builder.label :uni_id, "University" %>
<%= builder.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
<% end %>
<% end %>
fields_for takes your model's associated objects and automatically creates the fields you need. There is literally no need to "loop" - fields_for does it for you... if you set it up correctly.
The problem you have is you're building your associated objects at runtime, which is not only inefficient & against convention, but I think it will prevent the form_for from recognizing them (which is what allows fields_for to loop through them).
The above code should fix this for you.

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.

Why my code takes me to different URL?

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'.

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 tries to execute Update action instead of the one I want

I want to develop an ajax functionality for commenting posts in my website.
I've done this before, but I don't know why I'm having problems this time. Rails executes Update action from posts_controller, instead of the action called "save_comment".
This is the relevant line of my routes file:
map.connect "/posts/save_comment", :controller => 'posts', :action => 'save_comment'
This is the view's code:
<%= javascript_include_tag "prototype" %>
<% if logged_in? %>
<% remote_form_for :post, PostComment.new, :url => {:action => 'save_comment',:post_id=>inside_list.id}, :html => { :method => :put} do |f| %>
<p>
<%= f.label 'Comment' %><br />
<%= f.text_area :comment, :style=>'height:100px;' %>
</p>
<p>
<%= f.submit 'Publish' %>
</p>
<% end %>
<% end %>
The save_comment action looks like this:
def save_comment
comment = PostComment.new
comment.user_id = current_user.id
comment.post_id = params[:post_id]
comment.comment = params[:post][:comment]
comment.save
post = Post.find(params[:post_id])
render :update do |page|
page.replace_html 'dComments', :partial => 'post_comments/inside_list', :object => post
end
end
BTW: Is there a neater way for doing this?
You need to define the route method. Also you're not defining the post parameter.
map.connect "/posts/:post_id/save_comment", :controller => 'posts', :action => 'save_comment', :method => :post
Following convention you should make the route method => :post, rather than :put. Put requests are generally used for updating existing records, post for creating new. Also how about named routes?
#routes.rb
map.save_comment "/posts/:post_id/save_comment", :controller => 'posts', :action => 'save_comment', :method => :post
#view
<% remote_form_for :post, PostComment.new, :url => save_comment_path(inside_list.id) do |f| %>
Also, guessing here but do you have this defined:
map.resources :posts
if you do then add the new method
map.resources :posts, :member => {:save_comment => :post}

Resources