Updating Rails Params with Javascript - ruby-on-rails-3

Is it possible to change the value in the Params hash when a Javascript function is called?
I have a hidden Div, say DIV1 that becomes visible based on the selected value in a select field, within DIV1, I have a readonly textfield whose value is set to a value returned by a helper method.
This helper method uses a dynamic find_by that depends on the value of Params,but I guess the param Hash doesn't change when the value of the select Changes (since it isn't a full page refresh?). Please, how do I Achieve updating this so that when the select Value changes, the new value is reflected in the params hash. I have :remote=>true in the form_for tag. Is there a better approach than mine?
The Select field in a rails view
#finance_year
<%=f.select :financeyear, options_for_select(finance_year),{ :include_blank => 'Select a
Financial Year' } %>
and a an onchange event for that select
jQuery ->
$('#finance').hide()
value = "Select a Financial Year"
$('#finance_financeyear').change ->
selected = $('#finance_financeyear :selected').text()
$('#finance').show()
$('#finance').hide() if selected is value
the helper Method
def amount_owed(student)
financeyear = params[:financeyear]
#thisstudent = Finance.find_last_by_user_id(#student.user_id,
:conditions => {:financeyear => financeyear } )
if(#thisstudent)
#amount_owed= #thisstudent.amount_owed
else
student.department.amount
end
end
I appreciate any help and I hope I've been able to ask the question intelligently.

The answer is AJAX.
First, we'll need to add a new route to config/routes.rb to make amount_owed() a true action:
get '/finance_years/amount_owed/:student_id/:financeyear' => "finance_years#amount_owed"
Next, we'll create a default view to be returned whenever the amount_owed() action is called:
/app/views/finance_years/amount_owed.html.erb
<%= #amount_owed %>
So, that part was easy. Now we need to edit the amount_owed action so it will work with our parameters:
/app/controllers/finance_years_controller.rb
def amount_owed(student)
financeyear = params[:financeyear]
#thisstudent = Finance.find_last_by_user_id(params[:student_id],
:conditions => {:financeyear => financeyear } )
if(#thisstudent)
#amount_owed= #thisstudent.amount_owed
else
#amount_owed = student.department.amount
end
end
This way, we can pass in the finance year and the student id from the params hash and get an amount_owed every time. Now, to give our coffeeScript access to the current student_id and finance_year variables, I'd add a couple hidden fields to the form in the view file:
/app/views/finance_years/_form.html.erb
<%= hidden_field_tag :student_id, #student_id %>
<%= hidden_field_tag :finance_year, #finance_year %>
The last trick is to edit the coffeeScript, firing an asynchronous GET request whenever the select box changes.
/app/assets/javascripts/finance_years.js.coffee
$('#finance_financeyear').change ->
student_id = $("#student_id").val()
finance_year = $("#finance_year").val()
selected = $('#finance_financeyear :selected').text()
$('#finance').show() unless selected == value
$.get "/finance_years/amount_owed/#{student_id}/#{finance_year}", (response)->
$('#finance input[type=text]').load(response)
And that's about all I can do being away from my rails development machine. Let me know if additional problems arise.

I'm not a rails expert, but you're not going to be able to modify server side code directly from javascript. You will need to make a call down to the server (either on a form submit or through an ajax request) to tell the server to update itself.
To clarify, the server code is responsible for the initial rendering of the page, but once the template has been rendered it doesn't exist on the client page. So you can't directly modify it from coffeescript/javascript. You need to send a request back to the server to handle that.

Related

Rails3 Autocomplete Gem - Two Different Autocompletes on Same ClassName and Method

I am successfully using the ":scopes =>" option of this gem to return a subset of the rows of the table. Now I want to create a nearly identical autocomplete, on the same ClassName and Method, with a different scope, for a different view.
The problem is, the first two arguments of autocomplete in the controller are ClassName and Method, and those also create the functional name of the autocomplete function, as it is used in the view and route. Therefore, both of my autocompletes would have the same name.
Is there a workaround I can use to assign a different name to each of the similar autocompletes?
Example code:
autocomplete :my_class_name, :my_method, :display_value => :my_formatting_method,
:extra_data => [:id], :scopes => [:active_and_special]
def active_and_special
where("active = ?", true).
where("special = ?", true).
order("name ASC")
end
Then the again for the 2nd one, with the same class-name and method, but a different scope.
Best workaround I've found is to use "column_name" to override the part of the naming which ordinarily refers to the method - like this:
autocomplete :my_class_name, :foo, :column_name => 'my_method',
:display_value => :my_formatting_method, :extra_data => [:id],
:scopes => [:active_and_not_special]
def active_and_not_special
where("active = ?", true).
where("special = ?", false).
order("name ASC")
end
This has route:
get 'my_class_names/autocomplete_my_class_name_foo'
Whereas the original has route:
get 'my_class_names/autocomplete_my_class_name_my_method'
This allows us to generate a 2nd, different autocomplete, on the same Class and Method as another, with its own unique name.
Having an independent name, vs the 'magic' autogenerated one (to save 1 second of typing?) would prevent this trouble - or am I missing something?
I'll leave this open for a bit to see if anyone has a better solution.

Rails 3 Validation that only gets triggered once to simulate a warning on new records

I was wondering what the best implementation for displaying a warning for a particular field being sent to the database.
To give you an example, somebody provides data which is considered valid, but questionable. So we want to treat it as if it was a regular validation error on the first go and confirm that it's what the user actually wants to enter. At this point they will have the option to either continue or change the data being entered. If they choose to continue they'll be given the go-ahead and we'll skip that validation on the next run-through.
However (and this is the part I'm not sure about), if they change that field to another value that can be considered questionable we want to take them through the same process. Keep in mind these are new records and not records that have already been persisted to the database.
Can such a feat be accomplished with basic conditional validations? Would there be a better option?
Just to clarify my application knows exactly how to handle this questionable data, but it's going to be processed differently than normal data and we just want to inform the user ahead of time with a warning.
Currently the validation is your typical custom validation method that dictates the validity of an object.
validate :some_field_some_rules
def some_field_some_rules
if some_conditions_must_be_true
errors.add(:some_field, "warning message")
end
end
Edited, let's try with a custom validation that will be triggered only when you need to.
class MyModel < ActiveRecord::Base
attr_accessor :check_questionable
validate :questionable_values_validation, on: :create, if: Proc.new { |m| m.check_questionable }
def initialize
check_questionable = true
end
private
def questionable_values_validation
if attribute1 == "Questionable value"
self.errors[:base] << "Attribute1 is questionable"
check_questionable = false
end
end
end
Then, when you render the create form, be sure to add an hidden_field for check_questionable :
f.hidden_field :check_questionable
So the first time, when calling the create action, it'll save with check_questionable = true. If there's a questionable value, we add an error to ActiveRecord standard errors AND set the check_questionable to false. You'll then be re-rendering the new action but this time with the hidden_field set to false.
This way, when the form is re-submitted, it won't trigger questionable_values_validation ...
I didn't test it, might need some tweak, but it's a good start I believe!

Ruby on Rails: Basic parameterized queries and URL formation

I'm trying to learn how to query a rails database and return the results as JSON. In my example, I want to query the data using the parameters, city and state.
So far, in my controller, I have gotten the following action to work.
def state
#bathrooms = Bathroom.where("state = ?" ,params[:state])
respond_to do |format|
format.json { render :json => #bathrooms }
format.js { render :nothing => true }
end
end
This is also my routing entry.
match '/bathrooms/state/:state',
:controller => "bathrooms",
:action => "state"
I can call this resource with the following URL:
http://localhost:3000/bathrooms/state/CA.json
That's all good but I don't know how to query by more than one parameter. Adding and AND clause in the controller seems to be easy enough.
BUT....I don't know how to
a.) Correctly write the routing entry?
b.) What would the URL look like if I tested it in a browser?
I've tried to understand rake routes but I must be missing something.
Could someone provide a basic example for what the action should look like? What the routing entry should look like and what does the URL to access the resource look like?
Again, if written in SQL, this is what I would like to be returned.
SELECT * from bathrooms WHERE city='Chicago' AND state = 'IL'
Any help appreciated.
You don't have to pass everything by the route - the URL also support GET parameters - those are the parameters you usually see after the question mark in the URL. You can add those GET parameters without changing your routes: http://localhost:3000/bathrooms/state/IL.json?city=Chicago. Then your can access the city parameter via params[:city]. but in your case, I think it will be better to use http://localhost:3000/bathrooms/index.json?state=IL&city=Chicago. You'll also need to change your routing to
match '/bathrooms/index',
:controller=>:bathrooms,
:action=>:index
and put the code in the index method of BathroomsController. You access the parameters the same - but the concept is different - you don't enter a state and look for bathrooms by city, you just look for bathrooms by state and city.
Anyways, you don't want to write the URL by hand - you want to a Rails helper or an HTML form generate it:
link_to "bathroom in Chicago, IL",:controller=>:bathrooms,:action=>:index,:state=>'IL',:city=>'Chicago'
If you want to use a form(to let the users choose their own state and city), you need to set it's method to GET:
form_tag {:controller=>:bathrooms,:action=>:index},:method=>:get do
and put state and city as fields.
It's also worth noting that while you can use SQL's AND to perform a search by multiple fields, you can also chain where methods: Bathroom.where(:state=>params[:state]).where(:city=>params[:city]).
You can put any arbitrary parameters in your querystring.
For example:
http://localhost:3000/bathrooms/state/CA.json?city=Chicago
your query looks like this:
#bathrooms = Bathroom.where("state = ? and city= ?" ,params[:state], params[:city])

finding id of nested attribute

I am very new to RoR so this may be very fundamental. My structure keeps getting a level deeper and I can't figure out how to find the id anymore.
First you have a Company which can have many Users. Users sign in and are authenticated and the current_user is saved in a cookie with the Session.
Since the User has one Company I can always find the Company.id through the current_user.
Next a Company has many Farms. In farms create I can get the company id from the user cookie and the farm id is new so that works, and in farm show Rails knows which farm it is supposed to show. So that level works.
Now I want to add that a Farm has many Blocks. I am adding Blocks through the associated Farm show page, but the Blocks_controller doesn't know what farm page it is on (as far as I can tell, if it can any info is appreciated).
Here is the FarmsController create that works:
def create
company_id = current_user.company_id
#company = Company.find(company_id)
#farm = #company.farms.build(params[:farm])
if #farm.save
flash[:success] = "farm created"
redirect_to root_path
else
render 'pages/home'
end
end
And this code just complains that it doesn't know what id I am talking about:
BlocksController
def create
#farm = Farm.find(params[:id])
#block = #farm.blocks.build(params[:block])
end
This is displaying on the associated Farm show page, so if there is a way to capture the id I would love to know what it is.
Thank you for your time.
The three easiest ways to get that id is to:
Pass in that farm_id using a hidden form field. When creating the link to your blocks/new form just pass in the farm_id ie use a path like new_blocks_path(:id => #farm.id) inside your blocks controller you will want to make sure that the farm_id is set on the Block model.
def new
#block = new Block
#block.farm_id = params[:farm_id]
end
Then if you are using form for the farm_id field (which should probably be of type hidden), it should contain the right id. Now change the first line in the "create" block method to
#farm = Farm.find(params[:block][:farm_id])
You can combine the process of adding the blocks and the farms using nested forms. Take a look at http://railscasts.com/episodes/196-nested-model-form-part-1 for how to do this.
You can use nested RESTful resources to make sure that within the blocks controller you always have access to the farm id. For more information about how to do this try take a look at http://railscasts.com/episodes/139-nested-resources

How to test a search controller action which has filters in Rails with RSpec?

We have a bar with filters in almost all of our table-based views in a rails app and we need to test the controller action.
An example of the code:
def index
#users = User.
with_status(params[:status]).
with_role(params[:role_id]).
search(params[:q])
end
The above methods are ActiveRecord scopes which are setup to be bypassed if the passed value if blank.
What I need to do now is spec it sanely and test all the esge cases:
no params passed
only role, only status, only search
role + status, role + search, ... (pairs of 2)
role + status + search
The basic spec example I have written is as follows:
context "when filtering by status" do
before do
1.times { Factory(:user, :status => "one") }
3.times { Factory(:user, :status => "other") }
end
it "returns only users with the provided :status" do
get :index, :status => "one"
assigns(:users).size.should == 1
assigns(:users)[0].status.should == "one"
end
end
I want to write a matrix that will mix and match the role, status and search params and generate the appropriate spec examples.
Is the Array#permutation the solution or is there a better way to do it?
I would test the scopes in the model, so make sure that they can handle the blank value correctly, and also handle the set value correctly.
Then inside the controller, I would test the expectation that the chain is called (use stub_chain). The fact that the chain will return the correct result is handled by the fact that each scope individually has the correct behaviour (you tested that), and the combined behaviour is ensured by rails/activerecord. You should test the passed parameters are handled correctly.
The code you built to test the matrix is very impressive. But for me I try to make sure that my tests are readable, I consider them a kind of documentation of what a piece code is expected to do. To me your code is not comprehensible at first sight.
Hope this helps.