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.
Related
On my site, moderators can flag spammy comments. When these comments are flagged, they get quarantined so they no longer appear in regular views, though they can still be seen in the administrative control panel. At the moment, I exclude them from regular views like so:
#comments = Comment.where(:flagged => false)
I do this in every controller that has comments in it, of which there are many. I get the feeling that there's a cleaner way to handle this in Rails. Perhaps somewhere in the comments model I can specify that when querying for comments, only retrieve those that aren't flagged. If so, how is that done? And even if that's not possible, is there some other way to dry this code?
u can use a default scope
default_scope where(:flagged => false)
see http://apidock.com/rails/ActiveRecord/Base/default_scope/class
the default scope can be ignored using unscoped. See http://apidock.com/rails/ActiveRecord/Base/unscoped/class
i would prefer using a scope rather a default scope since i dont have to override it when all the records are needed. Depends upon the frequency of fetching all/unflagged records.
Make a scope (named 'clean' for this example):
class Comment < ActiveRecord
scope :clean, where(:flagged => false)
end
Then use:
#comments = Comment.clean
For future-proofing, you may may want to add a class method called default_view which just calls clean and use that instead. As your 'default' needs change, just modify the default_view method.
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])
In a Rails application, I have a particular form with many fields for editing a resource. Since I also want to log what was changed for this particular resource, I need to know which params changed.
Currently in this form, I have duplicated every field in the form with hidden field tags, so in the controller every field is compared to the corresponding hidden field to determine if the value was changed. But it's a LOT of work in the view and in the controller.
Being relatively new to Rails, I'm finding all kinds of Rails "magic" as I go along, so I wonder: does the framework provide a way to do this for me? Or is this pretty much the only way?
ActiveModel has exactly what you're looking for, take a look at the examples in the docs...
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
person = Person.find_by_name('Uncle Bob')
person.changed? # => false
person.name = 'Bob'
person.changed? # => true
person.name_changed? # => true
person.name_was # => 'Uncle Bob'
person.name_change # => ['Uncle Bob', 'Bob']
person.name = 'Bill'
person.name_change # => ['Uncle Bob', 'Bill']
You can try Dirty attributes for this task.
#post.attributes = params[:post]
#post.changed # or changes if you want to see what values on which was changed
More on that you can find by this link: http://ar.rubyonrails.org/classes/ActiveRecord/Dirty.html
Also if you want to use versioning or auditing, try this gems (best ones are: paper_trail, acts_as_audited, vestal_versions):
https://www.ruby-toolbox.com/categories/Active_Record_Versioning
https://www.ruby-toolbox.com/categories/Active_Record_User_Stamping
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.
I'm aware that I can search queries by calling where() on a model as follows:
Post.where(:title => 'My First Post')
However, what if I don't know if the user wants to filter out the search parameters?
For example, I have a search form that has an optional title field. If the title is filled, the form should search for a title. If it is not, however, the form should just return all fields.
I tried doing something along the lines of
search = Post.all
if params[:title].present?
search.where(:title => params[:title])
end
However, Rails immidiately returns the result of the search when I call Post.all and I cannot further add conditions/
How do I do this?
Thanks!
.all is a 'finisher' method for arel and causes the query to actually be called (same goes for .each and .first). So, if you want to be able to keep building up the scope conditionally, .all should be the last thing called, if you want to call it at all.
Given that there really isn't much in the way of relations to chain here, it would seem that a simple one-liner with a ternary operator might do:
#posts = params[:title].present? ? Post.where(:title => params[:title]) : Post.all
... because when there is no :where clause scope, you couldn't later chain it to :all, anyway.