Cancancan Select Field - ruby-on-rails

I am trying to customize a field on a cancancan object:
projectsAPI = Project.accessible_by(current_ability).select('projects.name, projects.price * 5 as new_price')
respond_to do |format|
format.json { render :json => {
:project_data => projectsAPI
}
}
The problem is when I check the API results, it just returns all the project fields, without any of the stuff in the .select statement.
When I check the log, the query has the custom fields in it, but also has the rest of the fields from projects.
How can I customize the fields in the json API return of the cancancan objects?

How does the .to_sql look like?
Have you tried something like this with a sub query? That is how I often solve CanCan issues in regards to the joins it makes.
projectsAPI = Project.where("projects.id IN (?)", Project.accessible_by(current_ability).select(:id).to_sql).select('projects.name, projects.price * 5 as new_price')

Related

Rails API get params to a custom method

Am trying to filter some data from database but its not getting params. This is my method:
def user_orders
orders = Order.select { | item | item[:user_id] == params[:id] }
if orders
render json: orders, status: :ok
else
render json: {error: "No orders available"}
end
end
This is the custom routing
get "/orders/user/:id", to: "orders#user_orders"
and the response is an empty array. However if I pass in a number in the method like so:
orders = Order.select { | item | item[:user_id] == 27 }
I get back the filtered array as expected. How can I pass in a dynamic ID from the routing?
EDIT: if your parameters look like this:
Parameters: { … "order"=>{…"user_id"=>27}}
… then you need to access the user_id as params[:order][:user_id].
Otherwise your conditional is comparing nil to 27, which will return false, and so nothing is ever selected.
If you’re querying an activerecord model, I also recommend that you use Order.where(item: {user_id: params[:id]}) to find your list of orders, so that and rails can cast to the right type as well.
What does the line in the rails log say? It should start with GET /user/orders and it should list what parameters have actually been received. Alternatively you can use puts to check the content of params.

Problem with selecting elements with the same params

What i do wrong? I want to return every products which pass condition:
def show
products = Product.select{|x| x[:category_id] == params[:id]}
render json: products
end
When i write
def show
products = Product.select{|x| x[:category_id] == 1}
render json: products
end
it works why the first example doesn't work?
I am pretty sure that there is mismatch in data type.
1=='1' #will be always false
1==1 #will be true
'1'=='1' #will be true as well
And also check for nil value from params[:id]
Please make sure to change as follows
def show
products = Product.select{|x| x.category_id == params[:id].to_i}
render json: products
end
OR
The best solution as suggested by #Eyeslandic is to use .where as it will not check for mismatch in data type. And also you don't have to take care of nil value from params[:id].
You should really be using a where to stop sql from loading all your products.
#products = Product.where('category_is = ?', params[:id])
The being said, if you are sticking to rails restful conventions, the fact you have a param called :id that is the category_id suggests you are on the category controller. So maybe consider changing your logic to:
#category = Category.includes(:products).find(params[:id])
you can then access products via
#category.products
or if your not interested in the category too much maybe
#products = Category.includes(:products).find(params[:id])&.products

rails select query creating alias for attribute name

With the goal of creating a JSON string, the requirement is to use an existing attribute and assign it, in the JSON output, with the attribute name id.
#valids = Destination.limit(10).select(:name, :long_name, :other_code).as_json(except: :id)
except: :id is being invoked to avoid confusion, as other_code attribute is intended to be the id in the generated JSON.
this will then be transformed into valid JSON via
#valids.to_json
how can other_code be output as id ?
You can do this like that with a simple string instead of symbols.
Destination
.limit(10)
.select('name, long_name, other_code as id')
.as_json
Honestly am new to Ruby on rails but very experience with json and frontend application responses
You can try this. if it work, you can now try it with your database responses. Ensure that column id exist in that your database
def your_definition_here
respond_to do |format|
#valids='999'
format.json do
render json: {id: #valids}.to_json
#render json: {id: #valids.id}.to_json
end
end
end

Sending a query string to rails respond_to

I am rather new to ruby and rails development.
for the past little while, I have been trying to figure out how I can pass params/query string to a rails respond_to block. I am focusing on the json response.
Say I have the following
def index
#employees = Employee.all
respond_to do |format|
format.html
format.json { render json: #employees }
end
end
and I am looking to only get a json response containing employees who have an id that is greater than 500. What would be the best way to go about this.
I have been trying to make the json request using jQuery.ajax() and I know you can pass data to the server that is formatted to a query, but not sure how to make it work.
The above example is only hypothetical. I am only looking for a way to be able to use a query sting when wanting a json response.
Thanks for the help!
Whatever parameters are sent with the request (in the query string) should be available in your controller (check the params variable). Here's one way to get the Employees with id's at & above 500:
Replace
#employees = Employee.all
with
#employees = Employee.find(:all, conditions: ["id >= ?", 500])
Please note that you don't need to pass anything besides the format to that respond_to block.

Rails 3 multiple parameter filtering using scopes

Trying to do a basic filter in rails 3 using the url params. I'd like to have a white list of params that can be filtered by, and return all the items that match. I've set up some scopes (with many more to come):
# in the model:
scope :budget_min, lambda {|min| where("budget > ?", min)}
scope :budget_max, lambda {|max| where("budget < ?", max)}
...but what's the best way to use some, none, or all of these scopes based on the present params[]? I've gotten this far, but it doesn't extend to multiple options. Looking for a sort of "chain if present" type operation.
#jobs = Job.all
#jobs = Job.budget_min(params[:budget_min]) if params[:budget_min]
I think you are close. Something like this won't extend to multiple options?
query = Job.scoped
query = query.budget_min(params[:budget_min]) if params[:budget_min]
query = query.budget_max(params[:budget_max]) if params[:budget_max]
#jobs = query.all
Generally, I'd prefer hand-made solutions but, for this kind of problem, a code base could become a mess very quickly. So I would go for a gem like meta_search.
One way would be to put your conditionals into the scopes:
scope :budget_max, lambda { |max| where("budget < ?", max) unless max.nil? }
That would still become rather cumbersome since you'd end up with:
Job.budget_min(params[:budget_min]).budget_max(params[:budget_max]) ...
A slightly different approach would be using something like the following inside your model (based on code from here:
class << self
def search(q)
whitelisted_params = {
:budget_max => "budget > ?",
:budget_min => "budget < ?"
}
whitelisted_params.keys.inject(scoped) do |combined_scope, param|
if q[param].nil?
combined_scope
else
combined_scope.where(whitelisted_params[param], q[param])
end
end
end
end
You can then use that method as follows and it should use the whitelisted filters if they're present in params:
MyModel.search(params)

Resources