Rails - Submit form to controller action - ruby-on-rails

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.

Related

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

Searching in Rails

I have two models: Inbox and Equipments. They have has_many relation :through => :inbox_equipments
In Inbox view I have the next code
<%= form_for #inbox, :html => { :multipart => true } do |f| %>
<%= f.text_area :number, placeholder: "Enter inbox number" %>
<% Equipment.all.each do |equipment| %>
<%= check_box_tag :equipment_ids, equipment.id, #inbox.equipments.include?(equipment), :name => 'inbox[equipment_ids][]' %>
<%= equipment.name %>
<% end %>
<%= f.submit "Submit", class: "btn btn-large btn-primary" %>
<% end %>
I need text area for find (or filter) desired value of equipment in check_box_tag
Like this:
<%= form_tag equipment_index_path, :method => 'get', :id => "equipments_search" do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Find", :name => nil, class: "btn btn-small btn-primary" %>
Help, please.
Although your description was not the best, I think you're looking for ajax
I would do this:
Call From Ajax
Ajax will allow you to pull the other form from your Rails app as a partial, appending it as required. This will give you the ability to treat the form as an asynchronous request, removing any issue from the form itself
Here's what I'd do:
#app/assets/javascripts/application.js
$("input[type=checkbox]").on("change", function() {
$.ajax({
url: "controller/search",
data: $("input[name=inbox[equipment_ids]").serialize(),
error: function(data) {
alert(data)
}
});
});
#config/routes.rb
match 'search(/:search)', :to => 'controller#search', :as => :search, via: [:get, :post]
#app/controllers/your_controller.rb
def search
#results = Model.where(:id => params[:equipment_ids])
respond_to do |format|
format.js
end
end
#app/views/your_controller/search.js.erb
$("form").append(data)
This won't work out of the box, but it will give you some ideas as to what you can do

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

How to fragment cache "like" buttons ? (Rails 3.2, memcached)

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 %>

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