chourobin
chourobin

Reputation: 4114

Rails inspect a request header for "If-Modified-Since"

I am trying to build an API using Rails that will inspect the request header for "If-Modified-Since" and render only the objects that were modified past that date. The problem is I am stuck trying to obtain the value from the request header in the controller.

# API
def index
   @products = Product.where{updated_at > request.headers["If-Modified-Since"]}
   render "v1/products/index"
end

What is the correct way for extracting values from the request header?

Upvotes: 1

Views: 5033

Answers (3)

aust
aust

Reputation: 914

According to the W3 specifications, your method of using If-Modified-Since is completely valid. [1] The other responders here are incorrect in saying that it is non-standard or will corrupt your cache. It's not very RESTful and is not recommended to include state information within your data (such as GET parameters).

To answer you question, you can use stale? to generate either a 304 (if it hasn't been modified) or generate the actual content. Here's an example:

def index
  if_modified_since = request.headers['If-Modified-Since'] || DateTime.new
  @items = Item.where("updated_at > ?", if_modified_since).order(updated_at: :desc)
  if stale?(@items.first)
    render json: @items
  end
end

Note that this assumes @items always contains an item. You can tailor it to your needs if it doesn't always return something.

Upvotes: 3

Erik Peterson
Erik Peterson

Reputation: 4311

request.if_modified_since or request.headers["HTTP_IF_MODIFIED_SINCE"]

Be aware that this is a non-standard use of the header. It generally refers to whether any content of the page has changed since the time specified in If-Modified-Since, not that the page should only include the content which has changed.

You might also be interested in the stale? method.

Upvotes: 1

willglynn
willglynn

Reputation: 11510

First: If-Modified-Since is for HTTP cache validation. Please don't use it this way. Use a parameter instead.

To answer your question: request.headers[] is the proper way of accessing request headers. For reference, request is an ActionDispatch::Request object.

The problem here is how you're trying to express the constraint. You're passing a block into ActiveRecord's #where method, and the block doesn't make any sense (Symbol#>(String)?). You can express this as a SQL fragment, like:

Product.where("updated_at > ?", params[:last_update])

Alternately, you could drop in Squeel, and write:

Product.where{ updated_at > params[:last_update] }

Upvotes: 5

Related Questions