Params.sort.key how does it works? - ruby-on-rails

Can anybody using this in own projects? If yes, how? I know that it helps to minimize of attacks.
If I have in the following in my controller:
mail_id = params[:mail_id].to_i
user_id = params[:user_id].to_i
token = params[:token]
where should I write params.sort.key [and what i should write here?]

I believe that concept should work as follows:
You expect 'params' hash to look somewhat like this:
params = { :mail_id => 1, :user_id => 2, :token => 'foo' }
which means params.keys will return [:mail_id, :user_id, :token]
params.keys.sort will return keys sorted alphabetically:
[:mail_id, :token, :user_id]
So to verify if params are holding the exact keys you expect it to have, you can do:
if params.keys.sort == [:mail_id, :token, :user_id]
render :text => 'Serving your request'
else
render :text => 'Server understood the request, but refuses to serve it, since some of the requested data is missing'
end
You can verify the exact contents of your 'params' hash using logger.debug(params.keys) in your controller

Related

Permitting array of arrays with strong parameters in rails

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 => [] }])

what is activerecord.values.columnattribute

I got an events helper module that somebody coded in a rails application. I am working on a form that can allow someone to create a new event.
here is a part of the form
=form.input :sponsorship_type, collection: get_event_labels(:event_types), as: :select_other
=form.input :society_name
it used to be
=form.input :event_type, collection: get_event_labels(:sponsorship_types), as: :select_other
=form.input :society_name
per the client request I had to drop the event_type column from the events table and added this instead
t.string "sponsorship_type"
the old schema has this
t.string "event_type"
this is the module
module EventsHelper
LABEL_MAP = {
institutions: [::INSTITUTIONS, 'activerecord.values.institutions.name'],
event_types: [::EVENT_TYPES, 'activerecord.values.event_types'],
industries: [::INDUSTRIES, 'activerecord.values.industries'],
referrers: [::REFERRERS, 'activerecord.values.referrers'],
regions: [::REGIONS, 'activerecord.values.regions'],
cities: [::CITIES, 'activerecord.values.cities']
}.freeze
def get_event_labels(type)
if Geokit::Geocoders::IpGeocoder.geocode(remote_ip).country_code == 'TW' and type == :event_types
return {
'活動/班' => 'Activities/Classes',
'食品和飲料' => 'Food&Beverage',
'優惠券' => 'Coupons',
'現金' => 'Cash',
'器材' => 'Equipment',
'獎品' => 'Prizes'
}
end
Hash[
LABEL_MAP[type][0].map do |constant|
[I18n.t("#{LABEL_MAP[type][1]}.#{constant}"),
constant]
end
]
end
def remote_ip
request.remote_ip
end
end
what is this? [::EVENT_TYPES, 'activerecord.values.event_types']
i tried just changing all the event_types to sponsorship_type. and then I am getting a
': uninitialized constant SPONSORSHIP_TYPES (NameError)
Its probably because activerecord.values.sponsorship_types have no values. How do I access it and put in values?
what is this?
::EVENT_TYPES
my end goal is to return the hash
return {
'活動/班' => 'Activities/Classes',
'食品和飲料' => 'Food&Beverage',
'優惠券' => 'Coupons',
'現金' => 'Cash',
'器材' => 'Equipment',
'獎品' => 'Prizes'
}
as selection option for the user on the form.
EVENT_TYPES is a constant. It must be defined somewhere in that application, perhaps in the controller or somewhere in the config folder. Find it and define your SPONSORSHIP_TYPES in the same way.
activerecord.values.event_types looks like a localization key. Look into your localization files in config/locales/... for some yaml hash with this structure. Add a new node sponsorship_types in the same way.

Trying to master Ruby. How can I optimize this method?

I'm learning new tricks all the time and I'm always on the lookout for better ideas.
I have this rather ugly method. How would you clean it up?
def self.likesit(user_id, params)
game_id = params[:game_id]
videolink_id = params[:videolink_id]
like_type = params[:like_type]
return false if like_type.nil?
if like_type == "videolink"
liked = Like.where(:user_id => user_id, :likeable_id => videolink_id, :likeable_type => "Videolink").first unless videolink_id.nil?
elsif like_type == "game"
liked = Like.where(:user_id => user_id, :likeable_id => game_id, :likeable_type => "Game").first unless game_id.nil?
end
if liked.present?
liked.amount = 1
liked.save
return true
else # not voted on before...create Like record
if like_type == "videolink"
Like.create(:user_id => user_id, :likeable_id => videolink_id, :likeable_type => "Videolink", :amount => 1)
elsif like_type == "game"
Like.create(:user_id => user_id, :likeable_id => game_id, :likeable_type => "Game", :amount => 1)
end
return true
end
return false
end
I would do something like:
class User < ActiveRecord::Base
has_many :likes, :dependent => :destroy
def likes_the(obj)
like = likes.find_or_initialize_by_likeable_type_and_likeable_id(obj.class.name, obj.id)
like.amount += 1
like.save
end
end
User.first.likes_the(VideoLink.first)
First, I think its wrong to deal with the "params" hash on the model level. To me its a red flag when you pass the entire params hash to a model. Thats in the scope of your controllers, your models should have no knowledge of the structure of your params hash, imo.
Second, I think its always cleaner to use objects when possible instead of class methods. What you are doing deals with an object, no reason to perform this on the class level. And finding the objects should be trivial in your controllers. After all this is the purpose of the controllers. To glue everything together.
Finally, eliminate all of the "return false" and "return true" madness. The save method takes care of that. The last "return false" in your method will never be called, because the if else clause above prevents it. In my opinion you should rarely be calling "return" in ruby, since ruby always returns the last evaluated line. In only use return if its at the very top of the method to handle an exception.
Hope this helps.
I'm not sure what the rest of your code looks like but you might consider this as a replacement:
def self.likesit(user_id, params)
return false unless params[:like_type]
query = {:user_id => user_id,
:likeable_id => eval("params[:#{params[:like_type]}_id]"),
:likeable_type => params[:like_type].capitalize}
if (liked = Like.where(query).first).present?
liked.amount = 1
liked.save
else # not voted on before...create Like record
Like.create(query.merge({:amount => 1}))
end
end
I assume liked.save and Like.create return true if they are succesful, otherwise nil is returned. And what about the unless game_id.nil? ? Do you really need that? If it's nil, it's nil and saved as nil. But you might as well check in your data model for nil's. (validations or something)

Checking if ActiveRecord find returns a result

I'm trying to check if a find method returns a result. My find method is the following:
post = Post.find(:all, :conditions => { :url => params['url'] }, :limit => 1)
What would be a good way to check that post contains a result?
find :all returns an empty array ([]) if no rows are returned, so you can just use it this way:
post = Post.find(:all, :conditions => { :url => params['url'] }, :limit => 1)
unless post.empty?
# do something...
end
By the way, if you do find :all you're going to get an array, not a single row. If you're trying to get just one Post, it would be cleaner to use the find_by helper or find :first or just first instead:
post = Post.find_by_url params['url']
# or
post = Post.first :conditions => { :url => params['url'] }
# then...
if post
# do something...
end
You can try ActiveRecord::Base.exists? before
Post.exists?(:conditions => { :url => params['url'] })
Use the BANG! version of the find_by_url method to get it to raise an exception of it could not be found and then rescue it later on in that same method/action.
def show
Post.find_by_url!(params[:url])
rescue ActiveRecord::RecordNotFound
flash[:notice] = "The URL you were looking for could not be found."
redirect_to root_path
end
end
If you didn't raise an exception here I believe that Rails would show the public/404.html page.
if post doesn't contain any result it will be an empty list and then:
post.empty?
will return true.
it may be as simple as changing your finder to:
post = Post.find(:first, :conditions => { :url => params['url'] })
With this finder, post will either return a single value or nil. Because nil behaves like false in a condition statement, you can say something like the following:
if post
# do something
else
# do something else
end
Post.find_by_id(id_column_value)
will return nil rathering than blowing up your program when it can't find a record.
Of course, there's
x = Post.where(:any_column_name => value)
which always returns an array of results. In which case you could just run an
x.each {|t| f(t) }
or
y = x.map {|t| f(t)}
or of course,
x[0], x[1], etc
Sorry I got a little carried away there
Another way to do it is checking with ActiveRecord#any?.

Ruby Style Question: storing hash constant with different possible values

This is more of a style question, I'm wondering what other people do.
Let's say I have a field in my database called "status" for a blog post. And I want it to have several possible values, like "draft", "awaiting review", and "posted", just as an example.
Obviously we don't want to "hard code" in these magic values each time, that wouldn't be DRY.
So what I sometimes do is something like this:
class Post
STATUS = {
:draft => "draft",
:awaiting_review => "awaiting review",
:posted => "posted"
}
...
end
Then I can write code referring to it later as STATUS[:draft] or Post::STATUS[:draft] etc.
This works ok, but there are a few things I don't like about it.
If you have a typo and call something like STATUS[:something_that_does_not_exist] it won't throw an error, it just returns nil, and may end up setting this in the database, etc before you ever notice a bug
It doesn't look clean or ruby-ish to write stuff like if some_var == Post::STATUS[:draft] ...
I dunno, something tells me there is a better way, but just wanted to see what other people do. Thanks!
You can use Hash.new and give it a block argument which is called if a key is unknown.
class Post
STATUS = Hash.new{ |hash, key| raise( "Key #{ key } is unknown" )}.update(
:draft => "draft",
:awaiting_review => "awaiting review",
:posted => "posted" )
end
It's a bit messy but it works.
irb(main):007:0> Post::STATUS[ :draft ]
=> "draft"
irb(main):008:0> Post::STATUS[ :bogus ]
RuntimeError: Key bogus is unknown
from (irb):2
from (irb):8:in `call'
from (irb):8:in `default'
from (irb):8:in `[]'
from (irb):8
This is a common problem. Consider something like this:
class Post < ActiveRecord::Base
validates_inclusion_of :status, :in => [:draft, :awaiting_review, :posted]
def status
read_attribute(:status).to_sym
end
def status= (value)
write_attribute(:status, value.to_s)
end
end
You can use a third-party ActiveRecord plugin called symbolize to make this even easier:
class Post < ActiveRecord::Base
symbolize :status
end
You could use a class method to raise an exception on a missing key:
class Post
def self.status(key)
statuses = {
:draft => "draft",
:awaiting_review => "awaiting review",
:posted => "posted"
}
raise StatusError unless statuses.has_key?(key)
statuses[key]
end
end
class StatusError < StandardError; end
Potentially, you could also use this method to store the statuses as integers in the database by changing your strings to integers (in the hash), converting your column types, and adding a getter and a setter.
I do it like this:
class Post
DRAFT = "draft"
AWAITING_REPLY = "awaiting reply"
POSTED = "posted"
STATUSES = [DRAFT, AWAITING_REPLY, POSTED]
validates_inclusion_of :status, :in => STATUSES
...
end
This way you get errors if you misspell one. If I have multiple sets of constants, I might do something like DRAFT_STATUS to distinguish.
Take a look at the attribute_mapper gem.
There's a related article that shows how you can handle the problem declaratively, like this (borrowed from the article):
class Post < ActiveRecord::Base
include AttributeMapper
map_attribute :status, :to => {
:draft => 1,
:reviewed => 2,
:published => 3
}
end
...which looks rather stylish.
Even though this is an old post, for somebody stumbling across this, you can use the fetch method on Hash, which raises an error (when no default is passed) if the given key is not found.
STATUS = {
:draft => "draft",
:awaiting_review => "awaiting review",
:posted => "posted"
}
STATUS.fetch(:draft) #=> "draft"
STATUS.fetch(:invalid_key) #=> KeyError: key not found: invalid_key

Resources