I'm using rabl 0.11.6 for my API, and I find myself doing the following over and over again for every date or time object:
node :created_at do |article|
article.created_at.iso8601
end
It would save a lot of code duplication, if the format for every date object could be set in one place, so that I just could use the attributes method like this
attributes :created_at
I found an issue on github (https://github.com/ccocchi/rabl-rails/issues/68) where they suggest, overwriting some Oj.default_options = { mode: :compat, time_format: :ruby } in an initializer. But I have no idea how to do a .iso8601.
Then I found this one https://gist.github.com/astevens/b80225d96d8889c946ac. But it looks like a hacky monkey patch solution.
And finally I found this issue https://github.com/nesquena/rabl/issues/336 where they overwrite the as_json method from ActiveSupport::TimeWithZone, also a very monkey-patch solution.
Is there no way to tell RABL what date and time format to use? And if not, what would be the best / least-hacky method to achieve this?
FWIW I fixed this problem in rails 4.2.8, Rabl 0.13.1 and OJ 2.18.5
Add a initializer with the following..
Oj.default_options = {:use_as_json => true}
As crazy as it sounds, this fixes it by changing the JSON serializer:
bundle add oj
I am building an app that involves a calendar. I found that the railscast for building a calendar although dated proved to be very helpful. I have everything up and running I am just trying to allow for the contents on each date to be organized by the datetime and not just the date so they appear in the right chronological order.
My current controller looks like this:
def index
#lessons = Lesson.all
#lesson_by_date = #lessons.group_by { |i| i.lesson_date.to_date }
#date = params[:date] ? Date.parse(params[:date]) : Date.today
end
Any help would be greatly appreciated. Thanks
I'm going off the assumption your question is how do I organize my #lessons by datetime. There are a few different scenarios I'll mention. I'm a bit limited since I don't know from your post how you've organized your schema for the table, but I think the controller gives me a ballpark idea.
1)
You should replace:
#lesson = Lesson.all
#lesson_by_date = #lessons.group_by { |i| i.lesson_date.to_date }
with something that's quicker:
#lesson_by_date = Lesson.order('lesson_date')
2)
If you're wondering why your current code isn't working it's because your group_by block is trying to convert i.lesson_date to a date IE to_date. Instead you may want to try to_datetime.
3) I would review http://apidock.com/rails/ActiveRecord/QueryMethods/order
I am using ruby 1.8.7 and rails 2.3.2
The following code is prone to sql injection
params[:id] = "1) OR 1=1--"
User.delete_all("id = #{params[:id]}")
My question is by doing the following will be the best solution to avoid sql injection or not. If not then what is the best way to do so?
User.delete_all("id = #{params[:id].to_i}")
What about:
User.where(id: params[:id]).delete_all
Ok sorry for Rails 2.x its:
User.delete_all(["id = ?", params[:id]])
Check doc
Btw, be sure you want to use delete_all instead of destroy_all, the former doesn't trigger callbacks.
You can use this also
User.delete(params[:id])
The other answers answer this well for Rails and it'll work fine if you follow their suggestions. In a more generic setting when you have to handle this yourself you can typically use a regular expression to extract a value that's in an expected format. This is really simple with an integer id. Think of it like this:
if params[:id] =~ /(\d+)/
safe_id = $1.to_i
# do something with safe_id now
end
That gets a little more complicated when you're handling strings and arbitrary data. If you have to handle such data then you can use the quoting methods available for the database adapters. In Rails this is ultimately rolled into a consistent interface:
safe_string = ActiveRecord::Base.connection.quote(unsafe_string)
For most database systems this will handle single quotes and backslashes in a special manner.
If you're outside of Rails you will have to use the quoting methods specific to your database adapter, but usage is quite similar.
The takeaway:
If your data has a particular format, enforce the format with a regular expression
Otherwise, use your database adapter's quoting function to make the data "safe" for use in a query
Rails will handle most of this for you if you properly use the various methods and "conditions"
Use the rails methods to pass your where options. You can always hardcode them, as in the example that you give, but the usual way would be something like:
User.where(:id => params[:id]).delete_all
User.where("id = ?", params[:id]).delete_all
User.where("id = :id", :id => params[:id]).delete_all
They are well tested and in case a new vulnerability is detected, an update will fix the problem and your code will not need to be changed.
By the way, if you just want to delete 1 record based on its id, what I would do is:
User.find(params[:id]).destroy
I'm in the U.S., and we usually format dates as "month/day/year". I'm trying to make sure that my Rails app, using Ruby 1.9, assumes this format everywhere, and works the way it did under Ruby 1.8.
I know that lots of people have this issue, so I'd like to create a definitive guide here.
Specifically:
'04/01/2011' is April 1, 2011, not Jan 4, 2011.
'4/1/2011' is also April 1, 2011 - the leading zeros should not be necessary.
How can I do this?
Here's what I have so far.
Controlling Date#to_s behavior
I have this line in application.rb:
# Format our dates like "12/25/2011'
Date::DATE_FORMATS[:default] = '%m/%d/%Y'
This ensures that if I do the following:
d = Date.new(2011,4,1)
d.to_s
... I get "04/01/2011", not "2011-04-01".
Controlling String#to_date behavior
ActiveSupport's String#to_date method currently looks like this (source):
def to_date
return nil if self.blank?
::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
end
(In case you don't follow that, the second line creates a new date, passing in year, month and day, in that order. The way it gets the year, month and day values is by using Date._parse, which parses a string and somehow decides what those values are, then returns a hash. .values_at pulls the values out of that hash in the order Date.new wants them.)
Since I know that I will normally pass in strings like "04/01/2011" or "4/1/2011", I can fix this by monkeypatching it like this:
class String
# Keep a pointer to ActiveSupport's String#to_date
alias_method :old_to_date, :to_date
# Redefine it as follows
def to_date
return nil if self.blank?
begin
# Start by assuming the values are in this order, separated by /
month, day, year = self.split('/').map(&:to_i)
::Date.new(year, month, day)
rescue
# If this fails - like for "April 4, 2011" - fall back to original behavior
begin
old_to_date
rescue NoMethodError => e
# Stupid, unhelpful error from the bowels of Ruby date-parsing code
if e.message == "undefined method `<' for nil:NilClass"
raise InvalidDateError.new("#{self} is not a valid date")
else
raise e
end
end
end
end
end
class InvalidDateError < StandardError; end;
This solution makes my tests pass, but is it crazy? Am I just missing a configuration option somewhere, or is there some other, easier solution?
Are there any other date-parsing cases I'm not covering?
Gem: ruby-american_date
This gem was created since I asked this question. I'm now using it and have been pleased.
https://github.com/jeremyevans/ruby-american_date
Date.strptime is probably what you're looking for in ruby 1.9.
You're probably stuck monkeypatching it onto string.to_date for now, but strptime is the best solution for parsing dates from strings in ruby 1.9.
Also, the formats are symmetric with strftime as far as I know.
you can use rails-i18n gem or just copy the en-US.yml and set your default locale "en-US" in config/application.rb
For parsing US-style dates, you could use:
Date.strptime(date_string, '%m/%d/%Y')
In console:
> Date.strptime('04/01/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
> Date.strptime('4/1/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
Use REE? :D
Seriously though. If this is a small app you have complete control over or you are standardizing on that date format, monkey patching for a project is totally reasonable. You just need to make sure all your inputs come in with the correct format, be it via API or website.
Instead of using to_s for Date instances, get in the habit of using strftime. It takes a format string that gives you complete control over the date format.
Edit:
strptime gives you full control over the parsing by specifying a format string as well. You can use the same format string in both methods.
Another option is Chronic - http://chronic.rubyforge.org/
You just need to set the endian preference to force only MM/DD/YYYY date format:
Chronic::DEFAULT_OPTIONS[ :endian_precedence ] = [ :middle ]
However the default for Chronic is the out-of-order US date format anyway!
HI
i would like to write a method that returns all the events that are on tomorrow or within the next 24 hours.
e.g
def tomorrows_events
#events = Event.will_occur_in next_24_hours
end
i have a datetime for each event which is called so to get it it would be, #event.date_and_time
i have the search logic gem installed but don't know if it supports dates, i couldn't find anything on it.
what would be the best way to write it? is there something in search logic i can use?
thanks
Event.all(:conditions => { :date_and_time => (Time.now.tomorrow.beginning_of_day)..Time.now.tomorrow.end_of_day})
I wrote a plugin that'll help you do this: http://github.com/radar/by_star.
You'd use this command for it:
Event.tomorrow(Time.zone.now, :field => "date_and_time")
Then it will return only results for tomorrow.