i am reading about Rack::Throttle and i want to change the default client identifier from an IP to somethng else. The documentation says it can be done
The rate-limiting counters stored and maintained by Rack::Throttle are
keyed to unique HTTP clients.
By default, HTTP clients are uniquely identified by their IP address
as returned by Rack::Request#ip. If you wish to instead use a more
granular, application-specific identifier such as a session key or a
user account name, you need only subclass a throttling strategy
implementation and override the #client_identifier method.
I have no clue where to add that in, here is my current subclass for another method. Does anybody know how to do this? https://github.com/datagraph/rack-throttle
module Rack
module Throttle
class DailyRequests < Daily
def allowed?(request)
## Insert rules
super request
end
end
class HourlyRequests < Hourly
def allowed?(request)
## Insert rules
super request
end
end
class RequestInterval < Interval
def allowed?(request)
## Insert rules
super request
end
end
end
end
You should subclass one of the existing rack-throttle classes (probably either Rack::Throttle::Interval or Rack::Throttle::TimeWindow, whichever one more closely aligns with your needs) and override the #client_identifier method.
#client_identifier is passed one argument, request, which is a Rack::Request instance containing information passed in the incoming HTTP request and can be used to get information such as HTTP headers, cookies, path, and possibly other info depending on your app. The default implementation looks like this:
# #param [Rack::Request] request
# #return [String]
def client_identifier(request)
request.ip.to_s
end
Here's an example of subclassing Rack::Throttle::Interval to match requests on a query parameter such as ?user_id=<id>:
class UserThrottle < Rack::Throttle::Interval
def client_identifier(request)
request['user_id']
end
end
which you could use in a Rack application with:
use UserThrottle, :min => 100
Notice you can still pass options like :min to the Rack use statement, since it is just subclassing the existing throttle classes. And adopting this in a Rails app would just involve calling use in your application.rb file (see Rails on Rack).
Related
In the ruby controller, I have two methods in the same controller.
class NotificationsController < ApplicationController
def first
variable_one = xxxx
end
def second
// do something
end
end
I want to use the variable one in the method first, and use it in the method two. I tried to assign the variable one to a session hash. session[:variable_one] = variable_one, and access it in the method two. But it turns out the session[:variable_one] in the method two is nil. These two methods don't have the corresponding views, so I cannot add a link_to and pass parameters. The method one cannot be set as before_action as well.
Could you please have some suggestions on this problem? Thanks so much.
The issue that session is stored via cookie, and therefore it is specific to one device. So, you will have one session between the rails app and your frontend, and another session betweeen the rails app and Twilio (probably the Twilio session will reset between each request). Basically, they're totally separate contexts.
Possibly you could figure out how to pass the information along via Twilio - see https://www.twilio.com/docs/voice/how-share-information-between-your-applications - but as a general-purpose workaround, you could just store the column on the database.
First, make a migration to add the column:
add_column :users, :my_variable, :string
Set this value in the first endpoint:
def first
current_user.update my_variable: "xxxx"
end
Then read it from the second:
def second
# first you would need to load the user, then you can read the value:
my_variable = current_user.my_variable
# you could set the db value to nil here if you wanted
current_user.update my_varible: nil
end
I set the flash message as below in one of my routes
def signup
flash[:is_signup] = true
... redirect_to route1 : route2 // based on some logic, redirect accordingly
end
def route1
// access flash[:is_signup]
flash.discard(:is_signup)
// do something
end
As depicted above, after i set the flash variable, i could redirect_to either the route(route1) that uses this flash variable or another route(route2) that doesn't care about this flash variable at all.
The issue is, when i redirect to route2, and then go on and mind my own business, hitting several routes/actions in the process, when i end up hitting the route1, the flash variable is still there.
I haven't seen anything in the documentation that says it is available until it is read. Is this the case? or am i doing something wrong?
Thanks in Advance
I'm seeing this as well (rails 4.2.11), and agree: no docs indicate access of flash should be necessary.
But, if I have a page that sets flash[:blah] = 'applesauce' and consumes the flash (e.g., puts flash[:blah]) on the next request, that key is not present in the following request. If I don't, it will linger through request after request until I hit a one where I check the flash.
My workaround is this:
In application_controller.rb
class ApplicationController < ActionController::Base
before_action :touch_flash
#...
def touch_flash
flash
end
end
This act of referencing flash appears to be enough to trigger a discard at end of the request (but doesn't interfere with any actual access later in the request). Next request, it's gone as expected.
I wrote a ruby gem to interact with a webservice. The gem contains the hardcoded value of client id and application secret.
So anyone else can use my data on his script and I will be charged for his requests. :(
On other hands it would be bad for the users if they have to create a new app in order to get a new personal application secret.
Any idea on how to store these info in a secure way?
While it might be OK to hardcode values in internal-only, early stage prototypes or temporary solution it is usually not advisable to hardcode values that normally change from application to application and most certainly not password or security tokens!
I would recommend that you made these values configurable in ways that people can easily set them via standard environment variables (very common in PaaS environments such as Heroku) or via initializers if need be. Exceptions are sane default values such as development database URLs (ex: redis' default 127.0.0.1:6379)
Example
module MyGem
class Configuration
attr_writer :client_id, :application_secret, :url
# Expects a MY_GEM_CLIENT_ID env var to be set in production
def client_id
#client_id ||= ENV.fetch('MY_GEM_CLIENT_ID', 'CLIENT_ID')
end
# Expects a MY_GEM_APPLICATION_SECRET env var to be set in production
def application_secret
#application_secret ||= ENV.fetch('MY_GEM_APPLICATION_SECRET', 'SECRET')
end
# ENV driven config but with working default
def url
#url ||= ENV.fetch('MY_GEM_URL', 'https://myservice.com/v1/api')
end
end
def self.configure(&block)
block.call(configuration)
end
def self.configuration
#configuration ||= Configuration.new
end
end
Initializer-based config of the code above
# config/initializers/my_gem.rb in Rails
# CustomConfigObject could be a Mixlib configuration object
MyGem.configure do |config|
config.client_id = CustomConfigObject.my_gem.client_id
config.application_sercret = CustomConfigObject.my_gem.application_secret
config.url = CustomConfigObject.my_gem.url
end
If you absolutely need to provide a default "sandbox" set of Client ID and Application Secret you can provide those values as defaults in the code above (the second argument to ENV.fetch()), but I'd recommend either adding a sandbox boolean setting that can be set to true/false and sent with API calls, at which point your API would process those as sandbox / dev calls or, preferably, add support for account-specific sandbox credentials.
I am using Restforce to query records from a remote salesforce instance. The user simply has to put in a valid UID for the record they want to query.
Restforce uses Faraday middleware to deal with http requests - and raises a Faraday::ResourceNotFound error if I request something that cannot be located in the remote salesforce database.
Question
Where should I validate user input?
I have two ideas but i'm not sure of the consequences to each... and I'm trying to work out how to stick best to the fat model - skinny controller best practice.
Check for successful query at the application controller level
Requests save the UID to a simple ActiveRecord model #record_request. My create method can fire a query, check for an error and flash/redirect the user if needed.
# app/controllers/record_requests_controller
def create
#record_request = current_user.record_requests.new(record_request_params)
# Check to see if CHAIN number exists
if #record_request.restforce.find("Contact", #record_request.chain_number, 'ClientID__c')
# If it gets past that do standard validation checks
if #record_request.save
flash[:success] = 'Record request was successfully created.'
redirect_to record_requests_path
else
render :new
end
end
end
Then over in the ApplicationController I've got a rescue method setup
# app/controllers/application_controller
rescue_from Faraday::ResourceNotFound, with: :resource_not_found
private
def resource_not_found
flash[:alert] = 'Cannot find resource on Salesforce'
redirect_to(:back)
end
This works! And seems fine... but...
Model level validation?
My gut tells me this is a validation and should be validated on the model level, what if there's a bug and something sneaks into my database? Should this all just be checked at the if #record_request.save moment?
If so... how would i get model level code to handle validation AND be able to fire off an external (OAuth authenticated) API request without breaking the MVC.
What are the implications to either, and how might I do better?
I think the best way to use model level validation something like this:
validate :something
def something
errors.add(:field, 'error message') unless RestClient.check_something
end
Where RestClient is singleton object in /lib folder. This will allow to keep controller clean.
I am attemping to create an object from a class. But the objects will be created when they are needed.. Code below a bit hard to explain
incoming_message = #message sent though inter webs
class Repeater
def initialize(username, ip)
#repeat incoming message to back to ip
end
end
incoming_message = Repeater.new(user, ip)
Now I can't do that Becuase incoming_message is not a constant.
How would I get around this?
EDIT:
To clear things up a bit. I do need to use this class to create multiple objects with diffrent names. The repeater is for a chat server where an incoming message from 1 user is taken in then sent back out all of the clients connected. Each new client that connects would have a object created with that specific IP address so that messages from others can be send to the client.
It would take in messages from the other users by everyone sending to the server on the same port read the message then write to clients what it received...
I hope this helped sorry for all the confusion :)
If you want to maintain some kind of global class-level state, you should define a class-level accessor on Repeater that you can assign your repeating message to.
class Repeater
class << self
attr_accessor :incoming_message
end
def initialize(username, ip)
# repeat Repeater.incoming_message to back to ip
end
end
Repeater.incoming_message = "what"
Repeater.new(user, ip)
You need to use some parsing + serialization . Can they wire an already serialized/marshalled string?
1) convert the ruby code to yaml or json
2) use the json or yaml load method like myobj = YAML.load(new_yaml_string)
or
save it in another file called input and do a
require 'input'
create object of repeater