Ransack Scoping issues
Hey everyone, Just posted this question to stack overflow but thought I'd give it a try hear. I've been trying to figure out how to scope ransack searching for a couple of weeks but haven't figured it out. Here's the link to my question. http://stackoverflow.com/questions/30578520/limiting-search-results-to-associated-model-with-ransack-gem
Any thoughts?
It looks like the main thing is that you need to set @school
in the action. Once you have that, you can either merge that into the params[:q]
search options or add where(school: @school)
into your query.
Can you access the school off the URL or the current user?
Thanks for the response. I added this to the pins controller:
def index
@school = School.find(params[:id])
@q = Pin.search(params[:q]).where(school: @school)
@pins = @q.result(distinct: true).order("created_at DESC").paginate(:page => params[:page], :per_page => 10 )
respond_with(@pins)
authorize @pins
end
When I search for a student name I get this error. "Couldn't find School without an ID"
In the url on the school's home page i have /schools/1. 1 is the id but when it goes to pin/index it looses the school id. Do I need to get re configure this to all happen in the school controller?
/pins?utf8=%E2%9C%93&q%5Buser_name_cont%5D=kid
That's where it takes me after I search fro /school/1
It might make sense to have pins nested under the school depending on what you're trying to accomplish. If you're trying to scope the pins to a school, that's what I would do. Then you can grab the school's ID from the url to filter the search.
The other alternative is to put a hidden field in the form to pass in the school_id_eq
parameter in the URL so that pins are filtered by that ID. This makes the pins controller generic, so it can be used for seeing pins from multiple schools.
I'm just trying to allow an admin user to search for a list of pins created by a user from their school by the user's name. I don't want them to be able to find pins of other users as it's sensitive data. It seems like your first idea would be better but I'm not entirely sure. How would I grab the id from the url ? In the routes file?
Gotcha, yeah you would definitely want to separate those then.
So here's how you can set that up (basically nested routes).
resources :schools do
resources :pins, module: :schools
end
This route basically generates /schools/:school_id/pins
(verify that with rake routes
).
That means you can query the school from the URL by doing @school = School.find(params[:school_id])
# app/controllers/schools/pins_controller.rb
class Schools::PinsController
def index
@school = School.find(params[:school_id])
@q = Pin.search(params[:q])
@pins = @q.result(distinct: true).where(school: @school).order("created_at DESC").paginate(:page => params[:page], :per_page => 10 )
respond_with(@pins)
authorize @pins
end
end
I moved the where
into the result line because that's where you're doing the other scopes so it fits a bit better. In general, I think that should work and should separate out things nicely between the schools.
You can also authorize @school
here to verify they can only ever see pins for their school as an added bonus.
Thanks! This is really cool. I appreciate the help. Testing it now.
I'll let you know if it works.
So I added all of the above. But I don't have a schools folder in my controller folder.
app/controllers/pins_controller.rb is where I put the code. When I run the search I get this error.
Routing Error
uninitialized constant PinsController::Schools
That's pretty clear where the error is. I tried creating a schools file and a second pins_controller.rb file with just the code in that but it didn't work. Instead of an error it just keeps redirecting to school/school_id
Edit: I did check the routes and they are working correctly /schools/:school_id/pins
So I added my routes.rb and rake routes output here. http://stackoverflow.com/questions/30578520/limiting-search-results-to-associated-model-with-ransack-gem
Rake routes is a bit tough because it's so long but I thought I'd just add the routes for pins and schools. Is that enough?
Yep! Routes are fine.
You want to put the code in the app/controllers/schools
folder so that it can detect it properly as the module. Just create it and store it in there and you'll be fine.
Also you want to have it inherit from ApplicationController because I forgot that part.
Might give this episode on nested routes a rewatch. This is where I touched on how the modules/nesting work for organizing your code into folders.
Thanks this is super helpful! I think I understand now from watching the video. I'll need to move my schools_controller.rb file and my pins controller.rb file into the app/controllers/schools folder. I'll also need to move my pins views folder into the view/schools folder. Is that right? I'll give it a shot today and let you know if it works.
Thanks again! really learning a ton.
That's all correct except I don't think you need to move the schools_controller.rb because it's a top level controller.
Good luck and fingers crossed it all works! :)
I got a no method error for pins_path in schools#show. So I changed the global search variable that's set in my application controller From
def set_global_search_variable
@q = Pin.search(params[:q])
end
To:
def set_global_search_variable
@q = School.search(params[:q])
end
the error goes away. When I search I now get a new error.
No route matches [GET] "/schools"
I don't think the answer is to change Pin to School. I tried School.pins.search but that's a no method error for pins in school#show. Added @pins =Pin.all to the show method and that's also not working. Started running around in circles with this so asking for a little more help. I think I'm close. Really appreciate your help