partial local only accessible using local_assigns, not exposed by name - ruby-on-rails-3

I am passing two locals from a view ERB to a partial. Both locals are successfully passed in local_assigns. However, I am only able to use the FormBuilder via a local variable name in the partial. The other value is usable within my partial as local_assigns[:disable_edits], but not as disable_edits.
_form.html.erb
<div>
<%= f.fields_for :panels do |builder| %>
<%= render "panel_fields", :f => builder, :disable_edits => true %>
<% end %>
</div>
_panel_fields.html.erb
<div>
<p>
<%= local_assigns[:disable_edits] %>
</p>
<p>
<%#= disable_edits ? 'disable edits true' : 'disable edits false' %>
</p>
<p>
<%= local_assigns.keys %>
</p>
local_assigns[:disable_edits] results in "true" being displayed.
local_assigns.keys results in "[:f, :disable_edits, :panel_fields]" being displayed.
Uncommenting the ternary statement results in "undefined local variable or method `disable_edits' for #<#:0x4d58768>"
I am following what I understand is the latest suggested Rails syntax, but have tried manipulations using :partial=>, :locals=>, :as=>, etc. to no avail. I also do not think I've made this an optional argument in any way, so a lot of the information about testing with has_key vs. nil? isn't helping me. My understanding is everything in local_assigns should be exposed as in the partial as a local variable with the same name as the hash key.
I'm getting by for now using local_assigns[:disable_edits], but would like to understand what is happening and correct things so I can use more conventional syntax. Thanks!

try using
render :partial => "panel_fields", :locals => {:f => builder, :disable_edits => true }

Related

How do I update a list of partials rendered with a collection after a form submission of a newly created object in ruby on rails

This is a portion of my groups view. I have a list of partials that I render with a collection of objects:
<div id="container">
<ul>
<li id="form"></li>
<li id="partials">
<%= render :partial => 'groups/partial-list-row', :collection => #allpartials, :as => :f %>
</li>
</ul>
</div>
In the list item with id "form" there is a ruby on rails form that is a form_for #newpartial which is defined in the Partial controller as #newpartial = Partial.new(). I have successfully used jquery to toggle the show and hide of the two list items on a "New Partial" button click, and upon completing a finished form, a new partial object is definitely created. What I'm looking for here is the collection of partials that reappears after the form submission includes the newly created partial object. What is the best way to do this? My form which sits inside the list item with id "form" looks like this:
<%= form_for #newpartial, :html => {:multipart => true, :class => 'custom'}, remote: true do |f| %>
<% if #newpartial.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#newpartial.errors.count, 'error') %> prohibited this partial from being saved:</h2>
<ul>
<% #newpartial.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render :partial => 'partials/form-partial', :locals => { :f => f } %>
<div class="actions">
<%= f.submit 'Launch', :class => 'large success button radius new_browser_tab' %>
<a class="cancel_campaign_new">Cancel</a>
</div>
<% end %>
I also have successfully created a function that is bounded to the "ajax:success" event of this form after the DOM is fully loaded. I just don't know if this is a right approach, and if it is, I don't know what the body of this event handler should consist of. I have created other questions relating to this same issue (I haven't found a solution to this for quite some time now). Here are the questions if you want additional context:
SO question 1
SO question 2
What I was failing to realize is that applying the remote: true on the form indicates that the controller's action method will respond with the models "action".js.erb file. After creating that file and performing the jquery I had always intended, I was able to fix a few kinks and got that part working.
The difference between putting the jquery to render the new partial in your client side javascript and your "action".js.erb file is that the "action".js.erb file is able to make the required request to the server, whereas your client side javascript is not.
Can someone read this and let me know if the above statements are accurate? I'd really like to provide an answer that is accurate as possible for anyone that comes across this...
There are some really good tutorials at CodeSchool.com which has some free courses to take that include video lectures, slides, and exercises that I used to finally give me enough guidance on this. Also worth mentioning that if you intend to learn this stuff quickly and plan on spending a lot of time developing your web development abilities, paying the 20 dollars a month for access to all the courses is well worth it (you can cancel at any time, so learn what you need to learn and move on!).

Why is my nested text_area helper adding html tags?

I have a text_area in a partial in a complex form that is called like so
<%= f.fields_for :notes do |notes_form| %>
<%= render :partial => 'note', :locals => {:f => notes_form, :operation => f, :count => operation.notes.count} %>
<% end %>
<p><%= add_child_link "Add note", :operation_notes %></p>
and the partial looks like this
<% count ||= 2 %>
<div class='fields'>
<%= f.text_area :note_text, :rows => "4", :class => "notes" %>
<%= remove_child_link "x", f, count %>
</div>
There can be many notes on the form hence the add and remove child links.
The issue I'm having is that if I add a note with the text 'abcd', when I bring up the edit form I get '<p>abcd</p>'. If there are line breaks in the note it adds <br /> tags. The text_area form helper seems to be using the simple_format helper but I have no idea why. Can anyone help as this is very undesirable behaviour?
Ah solved,
Earlier on the same page I was displaying the note and using simple_format to format it with
<%= simple_format note.note_text %>
It seems that simple_format is somewhat destructive as after this, a call to note.note_text always returns the formatted text. If I change the above to
<%= simple_format note.note_text.dup %>
then the note_text attribute is not altered and I get the appropriate results.
I will have to look more closely at simple_format but this really strikes me as undesirable behaviour.
EDIT
It looks like this has been corrected in Rails 3.1
I would suspect that you have something in your Note model that is processing the text. Check for callbacks in this model.

Correctly generate a form builder object while discarding the HTML without a deprecation warning

I have a partial which generates a div with some form fields in it. It uses the form builder variable "f" which is provided as input to correctly name the fields in the parameter has (fields are actually nested attributes, so the name is like "[author][book][0][title]").
I want to use that same partial when receiving an AJAX call to regenerate the div based on new user information. I am currently using <% form_for ... |f| %> in my erb file, but that generates a warning that "<% %>" is deprecated.
My erb file looks like the following:
<% if f.nil? %>
<% form_for(#author, :id => :coupon_form) do |f| %>
<%= render "books_detail1", :f => f %>
<% end %>
<% else %>
<%= render "books_detail1", :f => f %>
<% end %>
So what is the correct way to create a form builder context while discarding the generated HTML?
The correct answer is to use fields_for. It generates the same form builder object without the html. I lost track of this in it's use for sub-forms, but it's really the same thing.

Ruby on Rails: Custom Actions (Follow up)

This question is a follow up to this previous question: Ruby on Rails: Custom actions
As a follow up, what would be the syntax to use a custom action in a form_for? For my app, I have a partial called _invite_form.html.erb, and set the form to have a :url specification that I thought would link the form to the invite action on the Users controller:
<div id = "invite_form">
<h1>Invite</h1>
<%= form_for(invited, :url => invite_user_path) do |f| %>
<div class="field">
<%= f.text_field :email, :class => "inputform round", :placeholder => "email" %>
</div>
<div class="actions">
<%= f.submit "Invite", :class => "submit_button round" %>
</div>
<% end %>
</div>
This partial is called on certain pages, and this error is given:
"No route matches {:action=>"invite", :controller=>"users"}"
In my routes.rb file I have included the appropriate lines:
resources :users do
member do
get :invite
post :invite
end
end
Why is it that the route doesn't work? How do I change these files to make the form use the action "Invite" on the Users controller?
** Forgot to mention earlier: I defined invited in the Users helper: users_helper.rb:
module UsersHelper
def invited
#invited = User.new(params[:user])
end
end
As you don't have a persistent User just yet, make this a collection operation by:
Changing invite_user_path to invite_users_path in your controller
Changing member do to collection do in your routes
invite_user_path expects a user as an argument. Try invite_user_path(invited). You will also need to save the user before you can compute a path to it.
To experiment, go into rails console and see the difference between the following:
app.invite_user_path
app.invite_user_path(User.first)
app.invite_user_path(User.new)

Ajax Callbacks in Rails 3 with Prototype, not jQuery

I'm upgrading an app from Rails 2 to 3 and am reworking all of the remote functions to use Unobtrusive Javascript. Where I'm struggling is handling ajax callbacks in UJS.
There are a lot of resources I've found that show how to implement these callbacks with jQuery, but not much for prototype. Perhaps you can help me figure this out.
In Rails 2, I had this:
<% remote_form_for #foo, {:loading => "loading_function()", :complete => "complete_function()" } do |f| %>
...
<% end %>
In Rails 3, I have this:
<%= form_for #foo, :remote => true do |f| %>
....
<% end %>
From what I've figured out so far (which may be wrong), I need to attach my old loading/complete functions to the form so that they'll be fired by the handleRemote function in Rails.js. I'm just not sure how to go about that.
Again, I'm doing this in Prototype. So answers specific to that framework are appreciated.
The answer is the following:
<%= form_for #foo, :remote => true do |f| %>
...
<% end %>
...
<script type='text/javascript'>
$('edit_foo').observe('ajax:before', loading_function());
$('edit_foo').observe('ajax:complete complete_function());
</script>
Try this link. Yes, it is JQuery, but JQuery and Prototype do not differ the way how things work together. Here is a code fragment that adds a new task directly in the index page - and it uses Prototype:
views/tasks/_newform.html.erb:
<%= form_for(#task, :remote => true) do |f| %>
<div>
<%= f.label 'Add a new task: ' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
views/tasks/index.html.erb:
<div id='newform'>
<%= render :partial => "newform", :locals => { :#task => Task.new } %>
</div>
views/tasks/create.js.rjs:
page.insert_html :after, 'tablehead', :partial => #task
page.replace_html 'newform',:partial => "newform", :locals => { :#task => Task.new }
Edit: you need to add "format.js" to our create method of the task controller
For people with a similar issue, it may also help to look at the source code for the remote helpers in the Rails 2.3.x source code.
In my case, I wanted to figure out what to do with the ':update' parameter, as in:
remote_form_for(#obj, :update => "new_obj", :before => "some js code") do |f|
I had to find the update functionality in the remote_function code.
For my specific issue, it looks like it's impossible to get the equivalent of :update with Rails 3 UJS helpers. The rails.js in Rails 3 wraps :remote => true requests with the Ajax.Request(...), whereas the :update function in Rails 2 wraps Ajax requests with Ajax.Updater(...). For people looking to replace the :update feature from Rails 2, I see 2 options:
Switch to jquery-rails, so that you can access the response from the Ajax request, with code like this:
$("#elem").bind("ajax:complete", function(et, e){
$("#results").html(e.responseText);
});
Write your own Prototype based code to grab the form and submit it via ajax, using Ajax.Updater(...) instead of Ajax.Request. Do NOT use :remote => true, since this will attempt to use Ajax.Request.
Side note: I played around with the callback object provided in the ajax:complete event
$('new_obj').observe('ajax:complete', function(request){
console.info(request);
});
The request object doesn't appear to contain the response anywhere in it. It is pretty massive, though, so I could be wrong. Hopefully this will help someone else trying to upgrade from Rails 2 to 3, though.
There's a way to get the response from the Ajax.Request invocation, if you were using remote_form_for with :update option. So, you probably don't need to change it to use Ajax.Updater as a workaround. Basically, you use respone.memo.responseText, in your example it would be something like this:
$('new_obj').observe('ajax:complete', function(response){
console.info(response.memo.responseText);
// Probably you would use it like this:
$('new_obj').update(response.memo.responseText);
});