Is it possible to retrieve query string params in ActiveAdmin? - ruby-on-rails

I have an ActiveAdmin project that the user needs to select a category from a main page. They are then sent to a new product page with the category_id in the url (...blah?category_id=1) I want to be able to retrieve that category_id from the url. I keep getting an ActiveAdmin DSL error saying I can't params method
...blah?category_id=1
ActiveAdmin.register Product do
controller do
puts params[:category_id]
def scoped_collection
ItemsDesign.includes(:categories, :colors)
end
end
end
This what the AA controller should look like in order to get access to params.
controller do
def new
#blah = Blah.new
puts params[:category_id]
end
end

Figured it out. I the params needs to be inside an overriding method. In my case new as above.

Related

Passing a model object to a link generated by a named route

In my routes.rb file I have:
get 'search' => 'movies#search', as: :search_directors
And the search action in the movies controller looks like this:
def search
#movie = Movie.find(params[:id])
# other code
end
One of the views contains the following link:
= link_to 'Find Movies With Same Director', search_directors_path(#movie)
I was hoping that when this link is clicked, the ID of the #movie object will be available through params[:id] in the movies#search action. But instead, when I click on it Rails gives me this error:
ActiveRecord::RecordNotFound in MoviesController#search
Couldn't find Movie with 'id'=
The #movie object that I'm passing as a parameter to the route IS valid because other parts of the view is working properly (it is the show.html.haml view for the Movie URI).
You need to specify the id in your route, or pass it as an additional parameter (in that case it will be appended to the url as a GET param).
get 'search/:id' => 'movies#search', as: :search_directors
Or (for GET param):
= link_to 'Find Movies With Same Director', search_directors_path(id: #movie.id)
In the last case, you would have to add a condition in your search method to test if params[:id] is present at all.
Hope this will work for you...
def search
#movie = Movie.find(params[:id]) # this will raise ActiveRecord::RecordNotFound if id is not available in data base.
# you should use where instead of find
#movie = Movie.where(id: params[:id]).first # this will return nil if not found but not raise ActiveRecord::RecordNotFound Exceptaion.
# other code
end

(Rails) How to get 'id' out of edit url

I have a model called studies.
After action redirect redirect_to edit_study_path(#new_study),
URL: http://localhost:3000/studies/2/edit.
Is there anyway to customize an url after passing id ?
For example, http://localhost:3000/study
(still going to the edit path, and still with the :id in the params)
I guess what you want is to edit the current study?
In this case, it's possible, using ressource instead of ressources in the routes.
Let's have an example:
#in routes.rb
resources :studies
resource :study
Both of them will by default link to the StudiesController and call the same actions (eg. edit in your case) but in two different routes
get "/studies/:id/edit" => "studies#edit"
get "/study/edit" => "studies#edit"
in your edit action, you should then setup to handle correctly the parameters:
def edit
#study = params[:id].nil? ? current_study : Study.find(params[:id])
end
Note you need a current_study method somewhere, and store the current_study in cookies/sessions to make it works.
Example:
# In application_controller.rb
def current_study
#current_study ||= Study.find_by(id: session[:current_study_id]) #using find_by doesn't raise exception if doesn't exists
end
def current_study= x
#current_study = x
session[:current_study_id] = x.id
end
#... And back to study controller
def create
#...
#Eg. setup current_study and go to edit after creation
if study.save
self.current_study = study
redirect_to study_edit_path #easy peesy
end
end
Happy coding,
Yacine.

Action show to find value from hash instead of id

I am still learning rails and have done a lot of readings, but I am not very clear about how params, 'show' actions work yet.
For example we have UsersController, 'index' action is showing all the users with the code #user = User.all, and 'show' action is looking into each users, by using the code #user = User.find(params[:id])
I understand that they are all from the database, where User is a model.
However in my scenario, what if the data I am showing in views, doesn't go through database, instead in the 'index' action it is something like this -
#user = [{name => "alex"}, {name => "peter"}, {name => "john"}]
and in my 'show' action, how can I write the code so that it finds the users by name?
In your Rails app, the data that you show in your views, do not necessarily have to come from/through the database. You can always show any data you want in your views.
For example, in your index action, if you have this:
#users = [{name => "alex"}, {name => "peter"}, {name => "john"}]
Then, in your index view, you can show only those users by looping through the #users instance variable.
Same for show page as well.
If you want to show the users by name in your show page, you have to set the users by name in an instance variable e.g. #users_by_name:
#users_by_name = User.find_by(name: user_name)
# or you can hard code the values if you want like index action
and then this #users_by_name instance variable will be available in your show view so that you can loop through that and show the user names.
Originally, the show page is designed for showing a particular user related information, but you can show whatever information you want going against the conventions.
To be able to have a route like this: localhost:3000/users/alex that will show the user alex's information, you can add a route in your routes.rb file:
get 'users/:name', to: "users#show"
And, in your controller's show action, something like this:
def show
#user = User.find(params[:name])
end
Then, show the #user information in your view page.
P.S. This is not a good idea to find user by name as there might be more than one user with same name in the database and it will create conflict/ or give wrong data in such situations.
In show action , we search the user specific record not all.
So , we have to provide some unique identifiers as parameters to find the specific record.
For eg. Your view should be similar to the params we are passing as below:
<% #user.each do |user| %><br>
<%= link_to user.name, user_show_path+"?name="+user.name %><br>
<% end %><br>
In show action , write the code
def show
#user = User.find_by(:name => params[:name])
end
Also in routes.rb , write the below code:
get 'users/:name', to: "users#show"
For the above solution, make sure that name field will be unique.
My original question is that if it is possible for 'show' action not to go through database
Sure.
Your show action can be the following if you wanted it to:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = "me"
end
end
You really don't have to do anything specific in your application, Rails is just a framework and has certain conventions if you want it to work efficiently.
What you're asking is if you can populate your #user object from a third party set of data...
... Yes you can ...
The way to do it would be in the model, not the controller:
#app/models/user.rb
class User < ActiveRecord::Base
# populates from Hash
end
You'd then be able to populate the data in the controller from the model again:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.__________ #-> pull from your hash
end
end
finds the users by name
That's simple - just pass the name through the url: url.com/users/marine_lorphelin
This will set the :id parameter to marine_lorphelin, with which you'll be able to look up the name through your model:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User._______
end
end
If you were using a database with your user model, you'd be able to use the following:
def show
#user = User.find_by name: params[:id]
end
Since you're not, you'll have to attach your XML hash to your model somehow. This, I don't know without specifics such as where you're getting your data from, how you're accessing it, and which routes you're going to send to invoke it.

creating has_one association error Rails 4

I'm trying to create and order that is associated with an item.
An Order has one item:
class Order < ActiveRecord::Base
has_one :item
end
An Item belongs to an order:
class Item < ActiveRecord::Base
belongs_to :user
end
According to the guide this should work:
build_association(attributes = {})
create_association(attributes = {})
I have this in my controller:
def create
#order = #current_item.build_order(order_params)
#order.save
redirect_to #order
end
And this is the error I'm getting:
undefined method `build_order' for nil:NilClass
I know this has to do with how I've defined current_items but I've tried many different things and all lead to this same error message.
I have this in my application helper:
def current_item
Item.find(params[:id])
end
Can anyone point me in a better direction for how to define this or what I'm doing wrong here. Thanks for your help!
1) You don't have access to a helper method from the controller. You can include the helper class in your controller but it's a really bad practice. You must use helper methods only in the views.
2) You can move current_item method from the helper to the controller. Then there will be another problem. In your create method, you are trying to access instance variable #current_item which is not initialized at the moment, not the method. You can do it this way:
#order = #current_item.build_order(order_params)
to
#order = current_item.build_order(order_params)
Then current_item will return you Item object.
3) I am not sure what are your params, but you can implement it this way:
def create
#order = Order.new(params[:order])
#order.save
redirect_to #order
end
where params[:order] is for example:
{name: "order 1", item_id: 1}
You should change your create to use a method, rather a variable, so modify it as follows:
def create
#order = current_item.build_order(order_params)
#order.save
redirect_to #order
end
# rest of code
def current_item
Item.find(params[:id])
end
This should help.
Good luck!
The error you're getting is being caused by trying to run Item.find(params[:id]) but not passing it a valid value. It seems that params[:id] is maybe nil? Can you confirm this using a debugger or by temporarily adding raise "Params[:id] is set to #{params[:id]} to the first line of the method, running the code and seeing what it says in the terminal output?
All you need to do make this work is have a parameter value for the item come from the form that is being submitted. Normally rails uses the route/url to populate the value of params[:id]. For example, when the request is GET /items/1, params[:id] is 1.
In this case though, unless you've done some custom routing that you haven't shown in your question, creating a new order would usually be a POST to /orders and since there is no id in the url, params[:id] is nil.
It's up to you to add the item id from the order form. It would make sense that it would be sent with the rest of the order params as item_id, rather than just id, since id is usually used to reference the current object, which is a new order and therefore doesn't get have an id.
You'll need to make sure that item_id is whitelisted in your strong params with the rest of the values in the order_params method (I assume you defined this in the same controller but did not show it in the code), and then the code would look something like this.
def create
#order = current_item.build_order(order_params)
#order.save
redirect_to #order
end
#note the changes the the argument
def current_item
Item.find(order_params[:item_id])
end
def order_params
params.require(:order).permit(:item_id, :other_values_that_you_send)
end

Ruby / Rails - AJAX pagination of nested resources - How do I determine the parent resource?

My model has Posts, Users, and Comments. Users can leave Comments on/about Posts.
Every Comment belongs to a User and a Post.
Therefore, the Comment model has a user_id field and a post_id field.
When viewing a Post, I want to paginate through that Post's comments.
When viewing a User, I want to paginate through that User's comments.
I want to paginate using AJAX (via the Kaminari gem).
I have my nested routes set up for both.
On the Post, the URL being hit is http://localhost:3000/posts/{:id}/comments?page={page_number}
On the User, the URL being hit is http://localhost:3000/users/{:id}/comments?page={page_number}
Both URLs are hitting the index action of the Comments controller.
My question is this: inside the index action, how do I determine if the {:id} provided is a user_id or a post_id so I can retrieve the desired comments.
Check for params[:user_id] and params[:post_id] in your Comments controller:
if params[:user_id]
#call came from /users/ url
elsif params[:post_id]
#call came from /posts/ url
else
#call came from some other url
end
I like the Ryan Bates' way
class CommentsController
before_action :load_commentable
def index
#comments = #commentable.comments.page(params[:page])
end
private
def load_commentable
klass = [Post, User].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
end

Resources