Edit:
It turns out, this was really an issue of syntax when using render for partials. It should be render partial:
I am following this blog post guide to implement the acts_as_commentable_with_threading gem.
http://twocentstudios.com/blog/2012/11/15/simple-ajax-comments-with-rails/
I have a character model with the following comment form partial in the show.html.haml view.
This line is giving me an undefined local variable or method for 'comment'
app/views/characters/show.html.haml
...
= render 'comments/form', :locals => { comment => #new_comment }
...
The hash inside the locals hash seemed off to me, so i changed the comment local variable to :comment. This worked fine, but I don't believe that is I am supposed to do.
When I do this, the form partial that is rendered also uses a comment local variable.
app/views/comments/_form.html.haml
.comment-form
= simple_form_for comment, :url => comment_path, :remote => true do |f|
= f.error_notification
= f.input :body, :input_html => { :rows => "3" }, :label => false
= f.input :commentable_type, :as => :hidden, :value => comment.commentable_type
= f.input :commentable_id, :as => :hidden, :value => comment.commentable_id
= f.error :base
= f.button :submit, :class => "btn btn-primary", :disable_with => "Submitting…"
Notice that the object passed into the simple_form_for method is also a local variable. This raised an error too, and i turned it into a symbol as well. Next, the comment.commentable_type raised an error, naturally, because comment was not defined. I cannot turn this into a hash because it is having a method call on it, right?
Whatever the answer is to the question is, it seems like I am going about this the wrong way. I shouldn't be turning things into symbols, when the problem is really that it isn't defined. Where should I define it? Where and how should I define it? I tried simply doing comment in the comments controller,
I am using rails 4.0.0, using simple form, and haml. Could it be a bad syntax for simple form?
EDIT: it was a second line rendering the comment partial that was raising the error. (everything being named comment was making it hard to tell where it was coming from.
= render 'comments/form', comment: #new_comment
= render 'comments/a_comment', collection: #comments, as: :comment
-# partial for a single comment.
%div.comment{ :id => "comment-#{comment.id}" }
%hr
= link_to "×", comment_path(comment), :method => :delete, :remote => true, :confirm => "Are you sure you want to remove this comment?", :disable_with => "×", :class => 'close'
%h4
= comment.user.username
%small= comment.updated_at
%p= comment.body
%h4
In your controller:
def show
#character = Character.find(params[:id])
#new_comment = #character.comments.build
end
Assuming there is a has_many relation between character and comment.
In your view:
render partial: 'comments/form', locals: { new_comment: #new_comment }
or
render 'comments/form', new_comment: #new_comment
In your partial:
= simple_form_for new_comment, remote: true do |f|
Related
I am implementing comments in Rails 4 application.
I want to create comment and delete comment to work remotely with Ajax.
It works fine except the delete link for a newly added comment doesn't work.
What is the best way of making delete link work for a newly created item?
/views/posts/ show.html.haml
.post
%h1= #post.name
%h2 Comments
= render 'comments/form', comment: #comment
%ul#comments
= render 'comments/comment', :collection => #post.comments, :as => :comment
/views/comments/_form.html.haml
.comment-form
= simple_form_for comment, :remote => true do |f|
= f.input :body, :input_html => { :rows => "2" }, :label => false
= f.button :submit, :class => "btn btn-primary"
/views/comments/_comment.html.haml
%li{:"data-id"=>comment.id}
=comment.body
%br
= link_to "Destroy", comment_path(comment), :confirm => "Are you sure?", :method => :delete, remote: true, :class=>'link_comment_delete'
/views/comments/destroy.js.rb
$('#comments li[data-id=<%=#comment.id%>]').hide();
/views/comments/create.js.rb
$("#comments").append("<li><%= escape_javascript render #comment %></li>");
// ??? what to write here to make Delete link work
I've had the same exact situation, and ended up re-thinking the delete view by using .closest instead of biding to data-id, so you can do something like:
$("a.link_comment_delete").on('ajax:complete',function(e) {
$(this).closest('div.comment.body [or whatever class / id you are using]').fadeOut(100)
});
First we start off with conversations/index.html.haml to create a message
#new_message_conversation
.panel.panel-info
.panel-heading
%h4 Send a Bark!
.panel-footer(style="padding-top: 20px")
= simple_form_for :message, url: :messages, :remote => true do |f|
.form-group
= f.input :master_name, placeholder: 'Choose master...', label: false, :url => autocomplete_master_name_conversations_path, :as => :autocomplete, id_element: "#master_name_id", input_html: {class: "form-control"}
= f.input :recipient_id, as: "hidden", input_html: {id: "master_name_id"}
= f.input :body, label: false, as: "text", placeholder: 'Write message...', :input_html => { :rows => 5 }
= f.button :submit, 'Send', :class => "btn btn-lg btn-primary", :disable_with => "Sending..."
which then goes to the messages#create action which has
...
respond_to do |format|
format.js { render "create", locals: { conversation: #conversation, conversations: #conversations, receipts: #receipts }}
end
...
which sends the work to the conversations/create.js.erb file
$('#new_message_conversation').prop('disabled', true).html("<%= raw escape_javascript(render(:partial => 'conversations/show', locals: { conversation: conversation, receipts: receipts })) %>").hide().fadeIn('fast');
which adds the conversations/show partial, _show.html.haml which has
...
%ul.pager.pull-left(style= "padding-left: 10px")
%li#paginator_3= link_to_previous_page #receipts, "Newer", :remote => true, :param_name => 'page_2'
%li#paginator_4= link_to_next_page #receipts, "Older", :remote => true, :param_name => 'page_2'
...
everything works excepts now the pagination buttons don't work. and when I click a pagination button the server says
Rendered messages/index.js.erb
Why does a partial that's in views/conversations that has a remote ajax call render to a different controller (messages)? It should be rendering conversations/show.js.erb because the partial is conversations/_show.html.haml right?
here are my routes also
...
resources :conversations do
get :autocomplete_master_name, :on => :collection
end
resources :messages
...
Even though you're rendering views and partials from the conversations path, you never even touched the ConversationController.
You can render whatever views you want for the action you're executing. The only thing connecting the ConversationController with the views/conversation/file.html.erb and similar view files is a loose naming convention. When rendering say render 'index' from an action of the ConversationController, it just assumes by that convention you meant the views/conversation/index.html.erb file.
Your view or partial alone cannot reference the controller it would belong to (when going by the naming convention) because it is just used as a template by the render command in your action. The view doesn't care whether the controller behind it is the appropriate one. In this case, the render was originally executed in the MessagesController, so the view also just has a reference to that one.
To still have the links point to the correct controller, you need to specify the controller to be used for the url. Otherwise, it is assumed that you want to use the very same controller you used to render the page.
The culprit is probably somewhere in the link_to_previous_page and link_to_next_page helpers by kaminari. When using the full paginate helper, you can set the controller and action you want to use like this:
<%= paginate #users, :params => {:controller => 'foo', :action => 'bar'} %>
The documentation (here: https://github.com/amatsuda/kaminari) doesn't say whether this param is also possible with the other helpers, but the helper uses a simple link_to (see here: https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/helpers/action_view_extension.rb), so you should be able to do something like this:
link_to_previous_page #receipts, "Newer", {:controller => 'foo', :action => 'bar', :remote => true, :param_name => 'page_2'}
I have this form in a view in my project. I need to pass the task_id to a certain controller, but the log does not seem to be receiving the parameters. I don't know what the problem is.
<%= form_for :taskid, :url => {:action=>"index", :controller=>"statistics"}, :html => {:class => "nifty_form", :method => "GET"} do |f| %>
<%f.hidden_field :task_id, :value => task.id%>
<td><%= f.submit "اختر مهمة لاظهار احصائياتها منفرده"%></td>
<% end %>
You are missing on = after <%. The equal sign is needed whenever you want to the result appears on the HTML, so it is used with the field tags methods or render, for instance. You should not use the equal when using a if, for example, because this is not what you want to print (well, it can be, but most likely it isn't)
<%= form_for :taskid, :url => {:action=>"index", :controller=>"statistics"}, :html => {:class => "nifty_form", :method => "GET"} do |f| %>
<%= f.hidden_field :task_id, :value => task.id%>
<td><%= f.submit "اختر مهمة لاظهار احصائياتها منفرده"%></td>
<% end %>
However, as #AntonGrigoriev pointed out, you should use a object if you have, like this
<%= form_for #task, :url => {:action=>"index", :controller=>"statistics"}, :html => {:class => "nifty_form", :method => "GET"} do |f| %>
or you can simply use the hidden_field_tag
<%= hidden_field_tag :task_id, task.id %>
Hi please test with following code to send hidden value in rails, I have tried and worked for one of my application :
hidden_field_tag(name, value = nil, options = {}) public
eg:
<%= hidden_field_tag(:field_name,value=#offer_status)%>
Here is the relevant code from views/products/edit.html.erb:
<%= form_for(:product, :url => {:action => 'update', :id => #product.id}) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<%= submit_tag("Update Product") %>
<% end %>
from views/products/_form.html.erb:
<%= select_with_new_option(f, :shop, :name, :id) %>
and from helpers/products_helper.rb:
def select_options_with_create_new(objects, text_field, value_field, options={})
object = objects.to_s.singularize
all_objects = object.capitalize.constantize.all
all_objects = all_objects.sort_by(&options[:order_by]) if options.has_key?(:order_by)
select_options = all_objects.map{ |obj| [obj.send(text_field), obj.send(value_field)] }
select_options << [wrap_create_new_option("create new #{object}".titleize), "new_#{object}"]
options_for_select(select_options)
end
def wrap_create_new_option(str)
">> #{str} <<"
end
# By default, sorts by 'text_field'.
def select_with_new_option(f, object, text_field, value_field)
f.select(:"#{object}_id", select_options_with_create_new(object.pluralize, text_field, value_field, :order_by => text_field))
end
I expect the select box to be #product.shop_id by default, but this is not true (the first option is always the default value).
What am I missing ?
Alright, I got it. Just remove options_for_select(select_options) in the select_options_with_create_new method.
The options_for_select assembles the 2-d array select_options into a string of html options, which is accepted by the select form helper, however, without assigning the selected attribute. Just pass the 2-d array to the select method as the second argument, it would assign the selected automatically.
I think that, in this case, all you need to do is make sure you set #product in your edit action:
def edit
#product = Product.find(params[:id])
end
Then change your first line:
<%= form_for(:product, :url => {:action => 'update', :id => #product.id}) do |f| %>
to
<%= form_for(#product, :url => {:action => 'update', :id => #product.id}) do |f| %>
The first code block will certainly update the proper product, but you'll only see the current values reflected if you generate a form_for #product, with that #product variable set.
How do you build a helper method that looks like
-confirmation_for [#post, #comment] do |f|
= f.confirm "Post"
%p html here...
= f.edit "Edit"
and encapsulates two forms like
-form_for [#post, #commment] do |f|
= f.hidden_field :submission_state, :value => "confirmed"
= f.submit "Post"
%p html here...
-form_for [#post, #commment] do |f|
= f.hidden_field :submission_state, :value => "edit_requested"
= f.submit "Edit"
I don't think there's a way to get exactly what you're looking for without redefining form_for. Or writing your own version of it.
You can get close with FormBuilders or Partials or Helpers, but none of these concepts either alone will let you do what you're looking to do.
A FormBuilder will let you define methods to be invoked on the form, like confirm and edit, but they would be part of the same form. Unless you create two forms.
In the related helper file:
class ExampleFormBuilder < ActionView::Helpers::FormBuilder
def confirm
hidden_field(:submission_state, :value => "confirmed") + "\n" + submit "Post"
end
def edit
hidden_field(:submission_state, :value => "edit_requested") + "\n" + submit "Edit"
end
end
Sample usage:
- form_for [#posts,#comments], :builder => ExampleFormBuilder do |f|
= f.confirm
- form_for [#posts,#comments], :builder => ExampleFormBuilder do |f|
= f.edit
When used with a partial you could do something like this
partial:
- form_for [#posts,#comments], :builder => ExampleFormBuilder do |f|
= f.send(action)
view:
= render :partial => :confirmation_for, :locals => {:action => :confirm}
= render :partial => :confirmation_for, :locals => {:action => :edit}
You could then bundle both partial calls into another partial. But that's going a little too far.