Auto-update text field depending on selected option - ruby-on-rails

Rails ver: 4.0.0
Hi all,
In my form I have a drop-down selection of client names. I would like to have a text box containing the client's address be updated whenever the selection is changed (before clicking the submit button to finalize the update). The reason is I am working with legacy data from another project where there can be several client entries with the same name but different addresses (e.g. large corp with several offices).
Obviously (perhaps?) I can't use any of the client-side script solutions since the new address has to be retrieved from the model - unless there is a way for java/coffee script to do a db lookup that I don't know about (which is highly likely since I only have a superficial acquaintance with them).
Thanks for any hints or pointers.

You can do something like this assuming you have #client:
Add a hidden div to your view to hold a data attribute:
<div id="client_id" style="display:none;" data-client="<%= #client.id %>"></div>
In somefile.js.coffee:
App ||= {}
App.client =
address = $("#id_of_your_select_field")
client = $("#client_id).data('client')
toggler.on 'change', ( e ) ->
App.client.getAddress
getAddress: ->
$ajax(
type: 'post'
url: "/get_address"
client_id: client
success: ( data, status, xhr ) ->
# you could parse JSON here if you want, or keep reading and leave this blank
)
in routes.rb
post '/get_address/:client_id', to: 'clients#return_address'
in clients_controller.rb
def return_address
#client = Client.find(params[:client_id])
respond_to do |format|
format.js
end
end
and in views/clients/return_address.js do:
var clientAddress = $("#the_civ_with_the_address");
clientAddress.html( "<%= j render( :partial => 'clients/address', :locals => { :client => #client } ) %>" );
Then make a partial with the client info at app/views/clients/_address.html.erb

Related

Rails controller#update giving incorrect type for params

I want to update a model using controller#update. I want to do this via AJAX and without having a hidden form or any DOM elements to keep in sync with my JS data.
How can I submit data to a controller#update via jQuery ajax?
My JS:
$.ajax({
type: "PATCH",
url: "/uploads/" + current_upload.id,
data: {
"upload[user]": user.id,
"upload[upload]": current_upload.id
}
}).done(function( msg ) {
alert( "Data Saved: " + msg );
});
My Controller:
def update
#upload = Upload.find(params[:id])
# update the model.
if #upload.update(upload_params)
redirect_to #post
else
render 'edit'
end
end
private
def upload_params
# permit! allows all attributes.
params.require(:upload).permit(:user)
end
Error:
User(#70101060061080) expected, got String(#70101055761460)
Change "upload[user]": user.id to be "upload[user_id]": user.id.
Within Rails, it's trying to assign user (a user instance) to be the string you're passing in via user.id, and complaining about the type mismatch.
It sounds like your request parameters have the "upload" parameter set to be "13" rather than a hash.

best_in_place - use updated value back in view

I have an idea and a problem I can't seem to find answer or solution to.
Some info if required later or helpful:
Rails version 3.2.9
best_in_place (git://github.com/straydogstudio/best_in_place.git)
Ruby 1.9.3p327
Ok, so i have settings page where i can update individual setting by editing them with use of best_in_place gem. Works fine. Happy with that.
Some of the settings are interconnected, meaning, i have to sum or subtract them.
As a helpful tip for the user, in my view, right beside the in place form for that settings there is also a calculated value.
Now, of course, I would like to see this value be update along with the attribute itself.
I can't find a way to do that.
If i do it with the :data => it works, but i get the old and not the new value, so my view is always "1 step behind".
i have also tried with update.js.erb and _test.html.erb partial, but javascript file doesn't work. It is like it doesn't exist. I have double, triple checked where to put it and it is OK (app/views/controller/_partial.html.erb)
So. Pretty straightforward question would be; how can i access an updated value and use it back in view to update calculations. I personally think I should go with the partial and js file - but I have no clue why JS file isn't picked up. Any idea on that?
If there are any other options, i would more than appreciate the hint.
Thanks!
--EDIT (code added)
view:
<td>
<%= best_in_place #s,:pay_after_bonus, :display_with => :number_to_percentage, :type => :input, :nil => "Klikni tu za spremembo!", :cancel_button=> "Prekliči" %>
Cena: <span id="test"><%= number_to_currency(#s.family_member_price - ((#s.pay_after_bonus * #s.family_member_price)/100)) %></span>
</td>
settings_controller.rb:
def update
#s = Setting.find(params[:id])
respond_to do |format|
#s.update_attributes params[:setting]
#s.create_activity :update, :params => { :setting => params[:setting].keys.first }, owner: current_user
format.json { respond_with_bip(#s) }
format.js
end
end
update.js.erb:
$( "#test" ).html( "<%= escape_javascript( render( :partial => "update") ) %>" );
_update.html.erb:
<strong>Test</strong>
-- EDIT 2:
OK, apparently it is possible to do something like I want this way:
$('.best_in_place[data-attribute="model_attribute"]').bind(
"ajax:success", function(event, data) {
// function that will update whatever
});
in combination with
// respond to json request with
render :json => {"model" => #model}
&
"ajax:success", function(event, data) {
var result = $.parseJSON(data);
// from here the result var will be accessible with all the data returned by the controller.
// result.model is your object - use result.model.attribute to get specific values...
}
But here it ends for me.
I don't know how to use render :json => {"model" => #model} in my case, as it has to be done in combination with format.json { respond_with_bip(#s) }.
Where do I put render in controller?
Currently I get 500 internal server errors trying to do this as a response.
I have found this solution here.
Thanks!!
In the ajax callback you can make another request to get the partial you want:
$('.best_in_place.myclass').bind("ajax:success", function () {
$.getScript("http://www.someurl.com");
});
Then in the action you render a JS file (eg: show.js.erb), where you replace the target element with the results of the render:
$("#div-<%= #div.id %>").replaceWith("<%= escape_javascript(render(partial: 'some/partial', :layout => false)) %>");
You can use jQuery to parse the dom for the element that best in place just changed, and get the updated value from there. For example, of you have this code (haml)
= best_in_place #user, :name, :classes => 'name-edit'
Then your callback would look like this (coffeescript)
$('.name-edit').on 'ajax:success', (event, data, status, xhr) ->
newValue = $('.name-edit').html # could also use .attr() here
$('.some-other-widget').html(newValue) # again could also set .attr here
You can even skip looking up the new value with jQuery. In the context of the callback handler, 'this' represents the element the call was made from, so you could just do
$('.name-edit').on 'ajax:success', (event, data, status, xhr) ->
$('.some-other-widget').html this.innerHTML
and get the new value to the other widget that way. My guess is the event returned by the ajax handler also has currentTarget, which again would be the widget that trigged the ajax request. My only worry on all this would be that your success handler somehow beats the best in place handler, and you get the widget before it's updated. In my testing that hasn't ever happened.
I just answered a question like that:
Answer here
but instead of just inserting the value you need to use the sum that you need.

How to change the response format depending on the data sent?

I'm doing some controllers to render reports and here is my problem:
The user open a page with a form which let it change the download format and the date of the report.
The download format is set trough a select input.
When the user press the button I want to response depending on the selected format.
The problem is that it's specified trough the url. So trying to do something like:
case format
when "xlsx" then format.xlsx{...}
when "html" then format.html{...}
...
end
doesn't work because rails or the browser (I'm not sure) expects an html response.
I've though of two options:
Change the url of the form onsubmit which makes the application more dependent on javascript. Or.
redirect_to url + ".#{params[:download_format]}"
The second way looks better to me but I need to pass the :report_date in the url and I can't find the way to do it.
I've tried this:
url = my_custom_url_path
redirect_to url + ".#{params[:download_format]}", :date_format => params[:date_format]
But it's not working.
In the form:
<%= f.select :download_format, { "xlsx" => "xlsx, "Online" => "html" } %>
In the controller:
def action
if download_format = params[:download_format].delete
redirect_to my_action_path(options.merge( :format => download_format ) ) and return
end
# do some logic here
respond_to do |format|
format.xlsx{...}
format.html{...}
end
end

Partial not updated on first click

I am having problems with a remotely executed action and a partial that doesn't update the first time I click the link.
Inside the view (a partial named books) I am creating a link:
link_to "⊗", read_book_path(book), :remote => true
The read_book_path is defined in routes.rb
There is also a conditional that displays a different text when that book is read.
Inside my controller, I have defined a new action:
def read
#books = Book.all
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
respond_to do |format|
format.html { redirect_to(books_url) }
format.js {render :layout => false, :locals => { :book => #book } }
end
end
This means I need a file read.js.erb, this file's content is:
$("#books").empty().html("<%= escape_javascript( render(:partial => "books") ) %>");
When I click the link, I can see in the terminal window that the database field is updated but the partial is not. Clicking the same link again updates the partial.
Changing the link to :remote => false also works but the page reloads (as expected).
I have tried to debug it with Safari and the Developer tools and I can see the server's response when clicking the link for the first time.
Something is wrong there, the HTML generated by <%= escape_javascript( render(:partial => "books") ) %> contains the wrong HTML with the old content of the partial. Only the second or third click shows the updated HTML.
I have integrated jquery-ujs - is that the reason the partial doesn't update the first time or am I missing something else?
This really gave me a headache, can you help me?
Edit:
If that helps: I created a listener in application.js to ajax:before and ajax:complete. The first one shows a little spinner, the second one hides it.
When I click the link, the spinner shows but it doesn't hide.
It looks like you have an ordering problem that's causing the trouble. You're capturing a complete set of books into the #books variable and then modifying a separate copy of a single book. This change will not be propagated back.
# Load and modify the one book by flipping the flag
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
# Load all books
#books = Book.all
As a note this is an extremely inefficient way of doing things, so I hope you're not working on a large amount of data. You might find it's easier to do this by simply toggling the one field with a simple UPDATE query:
Book.update_all({ :read => true }, { :id => params[:id] })
I'm not sure why you're calling $(...).empty().html(...) instead of simply $(...).html(...) since the html() method should replace the HTML wholesale with no need to clear it in advance.
One thing that might help is using .js.rjs where the equivalent would be:
page[:books].replace_html(:partial => 'books')
With simple JavaScript, RJS allows you to eliminate a lot of the drudgery. You can use JS in RJS as well for cases where there is no equivalent:
page << '$("#books").empty()'
page[:books].replace_html(:partial => 'books')
To make this more Rails friendly, you could call your partial _book which would make the local variables redundant. Each partial has a default variable with a name matching the template name:
render(:partial => 'book', :collection => #books)

Rails - When calling NEW, create a record before displaying a form?

Here's what I'm trying to do.
when the user clicks new note.. I want the user to be taken to a page when they can start typing a note, and save it to the server all with AJAX..
Problem is, every time the page saves, it's making a new note.
This leads me to believe that when Rails gets the DEF NEW controller, some how I need rails to first make a NEW NOTE record and then redirect to the edit controller of that new note, where the user can create/edit the note all with AJAX.
Thoughts? Thanks.
I had the same problem once, creating the note first is probably a good idea.
Another way would be to send the user to the new action. When the first save occurs you send the new object back as a JSON object, and replace the form's action with the update url for that record as well as setting the form's method to put.
This way you don't end up with empty records in the database (with your use-case, you might want exactly that, so a User can continue a note later.)
Just my two cents.
Ok a way of implementing this could look like this:
Form
<%= form_for resource,
:remote => true,
:html => { 'id' => 'autosave' },
:url => resources_path(:format => :json) do |f| %>
...
<% end %>
Application JS
var $form = $('#autosave');
// bind to the first success event from the form
$form.one('ajax:success', function(data, status, xhr) {
// data contains our json object (your note as json)
// now we update the form
$form.attr('action', '/notes/' + data.id);
$form.attr('method', 'put');
$form.attr('data-method', 'put');
});
Controller
class ExampleController
...
def create
#
# respond with the json object if format = json,
# see the form above I'm passing the format with :url parameter in form_for
#
respond_with(resource) do |format|
format.json { render :json => resource }
end
end
end
If you really want use to use #new to create a note and save it, then you can simply do
def new
#note = Note.create # instead of Note.new
end
Rails will then display this note just like the #edit action, so the note id will be in a hidden field. Then when you send the Ajax calls, you'll be calling #edit. If you want to preserve the behavior of #new for when javascript is turned off, then you might want to create a different action.
def new
#note = Note.new
end
def new_js
#note = Note.create
end
When you load the page that has the link to new_note, include some javascript that changes the link to new_js_note. So when JS is off, you get the standard #new form. When JS is on, you get a form that is basically editing a preexisting blank note.

Resources