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}
Related
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 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
My Rails app has Post and Member models. Within posts/:id/show contains a "like" button which Members can click, or "Unlike" if #member has already "liked" this #post already.
(This button will link to a post action that does some ajax and makes the "like" button change into a "unlike" button)
Whats the best practice for caching the button? (below code obviously doesn't cache the button html).
Should I add :touch => true to member.rb, and then make a cache key for the button e.g. <% cache ['V1', #post, #member, 'like_button'] ? (seems redundant?)
post.rb
has_many :likes
like.rb
belongs_to :member
belongs_to :post
member.rb
has_many :likes
*posts/show.html.erb *
<% cache ['V1', #post, 'show'] do %>
<h1>#post.title</h1>
<div class="content">#post.content</div>
<% end %>
<%= render 'like_button', :post=> #post, :member => #member %>
** posts/_like_button.html.erb **
<% if member.liked_post?(post) %>
<%= link_to unlike_post_path(post), :method => :post, :remote => true, :class => 'btn' %>
<% else %>
<%= link_to like_post_path(post), :method => :post, :remote => true, :class => 'btn' %>
<% end %>
You can do something along these lines:
<% cache ['V1', #post, #member.liked_post?(#post), 'show'] do %>
<h1>#post.title</h1>
<div class="content">#post.content</div>
<%= render 'like_button', :post=> #post, :member => #member %>
<% end %>
This gives your 2 different cached versions of the fragment - one each for the 'liked' and 'not liked' states. This is better than 1 version per user.
YOu run the risk here of someone adding code to the like_button partial that uses more of the #member parameter, and that isn't part of the cache key, so you'll get incorrect results.
For this case, I'd change the like_button partial to take the same parameter as the cache call - #member.liked_post(#post) -- to make it clear that this is the only value used inside the partial code.
<%= render 'like_button', :post=> #post, :liked => #member.liked(#post) %>
With the new partial:
<% if liked %>
<%= link_to unlike_post_path(post), :method => :post, :remote => true, :class => 'btn' %>
<% else %>
<%= link_to like_post_path(post), :method => :post, :remote => true, :class => 'btn' %>
<% end %>
I have a'Remove' button in a show erb of the trackers_controller.show:
<%= form_for :user_tracker, :url => user_tracker_path,:method => :delete do |f| %>
<%= f.hidden_field :tracker_id, :value => #tracker.id %>
<%= f.submit :save, :value => 'Remove' %>
<% end %>
This works fine and calls user_trackers_controller.destroy
The User models looks like:
has_many :user_trackers
has_many :trackers, :through => :user_trackers
If I put the exact same button in another erb I get this error:
No route matches {:action=>"show", :controller=>"user_trackers"}
I have a few different combinations like :html => {:method => :delete }
If I try it this way
<% current_user.user_trackers.each do |user_tracker| %>
<%= user_tracker.tracker %>
<%= form_for user_tracker, :method => :delete do |f| %>
<%= f.submit :delete, :value => 'Remove' %>
<% end %>
I get the same routing error
Here are the routes:
user_trackers GET /user_trackers(.:format) user_trackers#index
POST /user_trackers(.:format) user_trackers#create
new_user_tracker GET /user_trackers/new(.:format) user_trackers#new
edit_user_tracker GET /user_trackers/:id/edit(.:format) user_trackers#edit
user_tracker GET /user_trackers/:id(.:format) user_trackers#show
PUT /user_trackers/:id(.:format) user_trackers#update
DELETE /user_trackers/:id(.:format) user_trackers#destroy
I do not understand, why will it not pick up that this is a destroy when in an unrelated erb?
Edit:
This is one seems to work but the html generates ids and classes like edit_user_tracker_7 but also the javascript to make it a delete so it seems I still have something wrong:
<%= form_for user_tracker, :url => user_tracker_path(user_tracker), :method => :delete do |f| %>
<%= f.hidden_field :tracker_id, :value => user_tracker.tracker_id %>
<%= f.submit :delete, :value => 'Remove from my portfolio' %>
<% end %>
in first line it should be
:url => user_tracker_path(#user)
Its not a bug, he just have to know who to remove :) so he needs id (in REST).
Also :method should be in :html
:html => { :method => :delete }
or
html: { method: "delete" }
with 1.9+ notation.
full form_for
user_tracker_path(#user), :html => {:method => :delete} do |f| %>
ofc if in your case #user is current_user then you have to swap it :)
Sorry for typos & english i'm not native :)
Cheers!
I have a form partial that needs to render a remote_form_for or a form_for depending on the value of a local variable passed into it from the caller view. It looks like...
<% if ajax %>
<% remote_form_for #search, :url => {:action => :search_set, :controller => :searches, :stype => stype} do |f| %>
<% else %>
<% form_for #search, :url => {:action => :search_set, :controller => :searches, :stype => stype} do |f| %>
<% end %>
Obviously, I am getting a syntax error near the <%else %>, because its expect an "end".
What's the right way to do this?
you could make a helper method
def form_or_remote_form_for object, *opts, &proc
if ajax
remote_form_for object, *opts, &proc
else
form_for object, *opts, &proc
end
end
and then in your views it'd just be
<% form_or_remote_form_for #search, :url => {:action => :search_set, :controller => :searches, :stype => stype} do |f| %>