I have one model which has a foreign key :
class Hotel < ActiveRecord::Base
belongs_to :country
scope :country, lambda { |country_id|
self.scoped.where('country_id IN ( ? )', country_id) unless country_id.blank?
}
end
And in my controller, i do this :
def filter
#hotels = Hotel.scoped
#hotels = #hotels.country(params[:country_id]) unless params[:country_id].blank?
count = #hotels.count
render :json => ['hotels' => #hotels, 'count' => count ]
end
But my json answer has the value country_id but not my contry entity, how can I force that?
Thank you.
You are using "country" as if it were scope, calling it on all Hotels. This isn't correct. I assume you are trying to get all Hotels that belong to country_id. You can do that like this:
#country = Country.find(params[:country_id])
render :json => ['hotels' => #country.hotels, 'country' => #country]
Does that solve your problem? Your question is a little confusing.
I have my answer, I have to use in my controller the :include parameter :
render :json => ['hotels' => #hotels, 'count' => count ], :include=> [:country, :city]
This will add my city and country models to my json answer.
Thank for help !!
Related
I have searched everywhere but does anyone know if it is possible to permit and array of arrays using strong parameters in rails? My code looks like this:
params.require(:resource).permit(:foo, :bar => [[:baz, :bend]])
This is giving me:
ArgumentError (wrong number of arguments (0 for 1..2))
I have also tried:
params.require(:resource).permit(:foo, :bar => [[]])
params.require(:resource).permit(:foo, :bar => [][])
params.require(:resource).permit(:foo, :bar => [])
But these all give me invalid parameter errors or do not process the parameters.
Thanks in advance for any help
Looking at the code I think this is not possible. you have to flatten the second level.
def permit(*filters)
params = self.class.new
filters.each do |filter|
case filter
when Symbol, String
permitted_scalar_filter(params, filter)
when Hash then
hash_filter(params, filter)
end
end
unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
params.permit!
end
Here's an example taken from rails strong parameter Github page:
params.permit(:name, {:emails => []}, :friends => [ :name, { :family => [ :name ], :hobbies => [] }])
No hair left on my head (and I have had lots :) ), I have been pulling out my hair and for the life of me I can't figure this out.
I have a one to many relations between 2 tables. I have installed the Datagrid Gem for reporting. I need to get the report from one model based on the other one.
Please have a look at my code.
reports_grid.rb
class ReportsGrid
include Datagrid
scope do
Land.includes(:estate)
end
filter(:estate, :enum, :select => proc { Estate.group("title").select("title").map {|c| [c.title] }})
column(:id, :header => "Land ID")
column(:current_stage, :header => "Stage")
column(:price)
column(:status)
end
reports_controller.rb
class ReportsController < ApplicationController
def index
#grid = ReportsGrid.new(params[:reports_grid]) do |scope|
if params[:reports_grid].present?
if params[:reports_grid][:estate].present?
scope.joins(:estate).where("estates.title = ? ",params[:reports_grid][:estate]).page(params[:page])
**# when I get the #grid.assets here all good and return correct number of rows**
else
scope.page(params[:page])
end
else
scope.page(params[:page])
end
end
end
end
Land.rb
belongs_to :estate
estate.rb
has_many :lands
Now when I go to /reports and try to run the filter I get the following error
PG::UndefinedColumn: ERROR: column lands.estate does not exist LINE 1: ..._id" WHERE (estates.title = 'Olive Gardens' ) AND "lands"."e... ^ : SELECT COUNT(*) FROM "lands" INNER JOIN "estates" ON "estates"."id" = "lands"."estate_id" WHERE (estates.title = 'Olive Gardens' ) AND "lands"."estate" = 'Olive Gardens'
Why is the Gem tries to add "lands"."estate" = 'Olive Gardens' to the query when I have defined it at the instance.
Please let me know if you need me to add anything. Thank you in advance.
Edit:
This is what I have done and worked in the Filter:
I have done this:
filter(:estate_id, :enum,
:select => lambda {Estate.all.map {|p| [p.title, p.id]}},
:multiple => false,
:include_blank => true
) do |value|
self.where(:lands => {:estate_id => value})
end
Do you it is a good approach?
I guess in the scope I could say Land.joins(:estate) then use the scope.all.map... in the query.
Datagrid filter designed to filter data but not to just be by default.
If you have some reason why estate should not filter data by itself then add :dummy => true option:
filter(:estate, :enum, :select => ..., :dummy => true)
But I'would recommend it. Do this instead and your hair will start growing instantly:
filter(:estate, :enum, :select => ...) do |scope, value|
scope.joins(:estate).where("estates.title = ? ", value)
end
It seems obvious from documentation here:
https://github.com/bogdan/datagrid/wiki/Filters#filter-block
Try using references
Land.includes(:estate).references(:estates)
How to permit this parameters:
contacts: [
{:value => 'value', :contacts_type => 'contact_type'},
{:value => 'value', :contacts_type => 'contact_type'},
]
To create many objects by controller action in one JSON request?
Like below, contacts will be an array of resources with specific attributes value and contacts_type:
params.permit(contacts: [:value, :contacts_type])
If you get params like the following:--
:params=>{:xyz => {:contacts => [{:value => 'value', :contacts_type => 'type'}, ..]}}
Then do the folowing:--
params.require(:xyz).permit(contacts: [:value, :contacts_type])
And add attr_accessor :contacts to your model if contacts is just a form field name part.
Work around for this should be
def contact_params
new_params = params.permit(contacts: [:value, :contacts_type])
new_params[:contacts] if new_params
end
Please suggest alternate solution if any
For example in my Car model i have such fields:
color, price, year
and in form partial i generate form with all this fields. But how to code such logic:
user could enter color and year and i must find with this conditions, user could enter just year or all fields in same time...
And how to write where condition? I could write something like:
if params[:color].present?
car = Car.where(color: params[:color])
end
if params[:color].present? && params[:year].present?
car = Car.where(color: params[:color], year: params[:year])
end
and so over....
But this is very ugly solution, i'm new to rails, and want to know: how is better to solve my problem?
Check out the has_scope gem: https://github.com/plataformatec/has_scope
It really simplifies a lot of this:
class Graduation < ActiveRecord::Base
scope :featured, -> { where(:featured => true) }
scope :by_degree, -> degree { where(:degree => degree) }
scope :by_period, -> started_at, ended_at { where("started_at = ? AND ended_at = ?", started_at, ended_at) }
end
class GraduationsController < ApplicationController
has_scope :featured, :type => :boolean
has_scope :by_degree
has_scope :by_period, :using => [:started_at, :ended_at], :type => :hash
def index
#graduations = apply_scopes(Graduation).all
end
end
Thats it from the controller side
I would turn those into scopes on your Car model:
scope :by_color, lambda { |color| where(:color => color)}
scope :by_year, lambda { |year| where(:year => year)}
and in your controller you would just conditionally chain them like this:
def index
#cars = Car.all
#cars = #cars.by_color(params[:color]) if params[:color].present?
#cars = #cars.by_year(params[:year]) if params[:year].present?
end
user_params = [:color, :year, :price]
cars = self
user_params.each do |p|
cars = cars.where(p: params[p]) if params[p].present?
end
The typical (naive, but simple) way I would do this is with a generic search method in my model, eg.
class Car < ActiveRecord::Base
# Just pass params directly in
def self.search(params)
# By default we return all cars
cars = all
if params[:color].present?
cars = cars.where(color: params[:color])
end
if params[:price1].present? && params[:price2].present?
cars = cars.where('price between ? and ?', params[:price1], params[:price2])
end
# insert more fields here
cars
end
end
You can easily keep chaining wheres onto the query like this, and Rails will just AND them all together in the SQL. Then you can just call it with Car.search(params).
I think you could use params.permit
my_where_params = params.permit(:color, :price, :year).select {|k,v| v.present?}
car = Car.where(my_where_params)
EDIT: I think this only works in rails 4, not sure what version you're using.
EDIT #2 excerpt from site I linked to:
Using permit won't mind if the permitted attribute is missing
params = ActionController::Parameters.new(username: "john", password: "secret")
params.permit(:username, :password, :foobar)
# => { "username"=>"john", "password"=>"secret"}
as you can see, foobar isn't inside the new hash.
EDIT #3 added select block to where_params as it was pointed out in the comments that empty form fields would trigger an empty element to be created in the params hash.
I have such index.rabl:
collection #exchangers, :root => "bank", :object_root => false
extends "exchanger_lists/show"
and such show.rabl:
object #exchanger
attributes :id, :name, :address, :location_id, :latitude, :longitude, :exchanger_type_id
node(:location_name) {|exchanger_list| exchanger_list.location.name }
node(:exchanger_type_name) {"normal" }
child #currencies do
attribute :value, :direction_of_exchange_id, :exchanger_list_id
end
my contoller is such:
def index
#exchangers = ExchangerList.all
end
def show
#exchanger = ExchangerList.find(params[:id])
#currency_list = CurrencyList.all
#currencies = []
#currency_list.each do |c|
#currencies << CurrencyValue.find(:all, :conditions => {:currency_list_id => c.id, :exchanger_list_id => #exchanger.id}, :order => :updated_at).last(2)
end
#currencies.flatten!
end
if i call in browser show method, i see child #currencies and it's data, but if i call index i see all (also i see nodes) but child i didn't see.... What's wrong? what i do bad?
Your architecture is a little bit messed up because in the show action you not only display an #exchanger but also the complete list of #currencies being nil when you render show in the index template. In general I would suggest you to think about the whole app architecture.
When I should give you a simple solution for you current problem I would extract the #currencies code from the show action into helper method in app/helpers/currencies_helper.rb and access it from the show template.
module CurrenciesHelper
def currencies(exchanger)
currencies = CurrencyList.all.map do |c|
CurrencyValue.find(:all, :conditions => {:currency_list_id => c.id, :exchanger_list_id => exchanger.id}, :order => :updated_at).last(2)
end
currencies.flatten!
end
end
By the way I replaced the each method with map because it suits better in this case.
Change the currencies part in the show template to
child currencies(#exchanger) do
attribute :value, :direction_of_exchange_id, :exchanger_list_id
end