Ruby: Model ActionController filters

ActionController filters provide a way to register callbacks that run
before, after or around an action (i.e. HTTP request handler). They run
in the same class context as the action, so can get/set instance
variables and generally interact with the action in arbitrary ways.

In order to track flow between filters and actions, we have to model the
callback chain. This commit does that. A later change will add dataflow
steps to actually track flow through the chain.
This commit is contained in:
Harry Maclean
2022-12-13 12:03:07 +13:00
parent 6c0b50c696
commit fb86ef4aac
12 changed files with 636 additions and 54 deletions

View File

@@ -14,6 +14,15 @@ private import codeql.ruby.frameworks.Rails
private import codeql.ruby.frameworks.internal.Rails
private import codeql.ruby.dataflow.internal.DataFlowDispatch
/**
* Provides modeling for ActionController, which is part of the `actionpack` gem.
* Version: 7.0.
*/
module ActionController {
// TODO: move the rest of this file inside this module.
import codeql.ruby.frameworks.actioncontroller.Filters
}
/**
* DEPRECATED: Import `codeql.ruby.frameworks.Rails` and use `Rails::ParamsCall` instead.
*/

View File

@@ -0,0 +1,362 @@
/**
* Provides modeling for ActionController filters.
*/
private import codeql.ruby.AST
private import codeql.ruby.frameworks.ActionController
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.controlflow.CfgNodes::ExprNodes
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql.ruby.ast.internal.Constant
/**
* Provides modeling for ActionController filters.
*/
module Filters {
private newtype TFilterKind =
TBeforeKind() or
TAfterKind() or
TAroundKind()
/**
* Represents the kind of filter.
* "before" filters run before the action and "after" filters run after the
* action. "around" filters run around the action, `yield`ing to it at will.
*/
private class FilterKind extends TFilterKind {
string toString() {
this = TBeforeKind() and result = "before"
or
this = TAfterKind() and result = "after"
or
this = TAroundKind() and result = "around"
}
}
/**
* A call to a class method that adds or removes a filter from the callback chain.
* This class exists to encapsulate common behavior between calls that
* register callbacks (`before_action`, `after_action` etc.) and calls that
* remove callbacks (`skip_before_action`, `skip_after_action` etc.)
*/
private class FilterCall extends MethodCallCfgNode {
private FilterKind kind;
FilterCall() {
this.getExpr().getEnclosingModule() = any(ActionControllerClass c).getADeclaration() and
this.getMethodName() = ["", "prepend_", "append_", "skip_"] + kind + "_action"
}
FilterKind getKind() { result = kind }
/**
* Gets an action which this filter is applied to.
*/
ActionControllerActionMethod getAction() {
// A filter cannot apply to another filter
result != any(Filter f).getFilterCallable() and
// Only include routable actions. This can exclude valid actions if we can't parse the `routes.rb` file fully.
exists(result.getARoute()) and
(
result.getName() = this.getOnlyArgument()
or
not exists(this.getOnlyArgument()) and
forall(string except | except = this.getExceptArgument() | result.getName() != except)
) and
(
result = this.getExpr().getEnclosingModule().getAMethod()
or
exists(ModuleBase m |
m.getModule() = this.getExpr().getEnclosingModule().getModule().getADescendent() and
result = m.getAMethod()
)
)
}
private string getOnlyArgument() {
exists(ExprCfgNode only | only = this.getKeywordArgument("only") |
// only: :index
result = only.getConstantValue().getStringlikeValue()
or
// only: [:index, :show]
// only: SOME_CONST_ARRAY
exists(ArrayLiteralCfgNode n |
isArrayConstant(only, n) and
result = n.getAnArgument().getConstantValue().getStringlikeValue()
)
)
}
private string getExceptArgument() {
exists(ExprCfgNode except | except = this.getKeywordArgument("except") |
// except: :create
result = except.getConstantValue().getStringlikeValue()
or
// except: [:create, :update]
result =
except.(ArrayLiteralCfgNode).getAnArgument().getConstantValue().getStringlikeValue()
)
}
StringlikeLiteralCfgNode getFilterArgument() { result = this.getPositionalArgument(_) }
/**
* Gets the callable that implements the filter with name `name`.
* This currently only finds methods in the local class or superclass.
* It doesn't handle:
* - lambdas
* - blocks
* - classes
*
* In the example below, the callable for the filter `:foo` is the method `foo`.
* ```rb
* class PostsController < ActionController::Base
* before_action :foo
*
* def foo
* end
* end
* ```
*/
Callable getFilterCallable(string name) {
result.(MethodBase).getName() = name and
// Method in same class
(
result.getEnclosingModule() = this.getExpr().getEnclosingModule()
or
// Method in superclass
result.getEnclosingModule().getModule() =
this.getExpr().getEnclosingModule().getModule().getSuperClass()
)
}
}
/**
* An argument to a call that registers a callback for one or more
* ActionController actions. These are commonly called filters.
*
* In the example below, the `before_action` call registers `set_user` as a
* callback for all actions in the controller. When a request is routed to
* `PostsController#index`, the method `set_user` will be called before
* `index` is executed.
*
* The `after_action` call registers `log_request` as a callback. This behaves
* similarly to `before_action` but the callback will be called _after_ the
* action has finished executing.
*
* The `around_action` call registers `trace_request` as a callback that will
* run _around_ the action. This means that `trace_request` will be called
* before the action, and will run until it `yield`s control. Then the action
* (or another callback) will be run. Once the action has run, control will be
* returned to `trace_request`, which will finish executing.
*
* Due to the complexity of dataflow around `yield` calls, currently only
* `before_action` and `after_action` callbacks are modeled fully here.
*
* ```rb
* class PostsController < ApplicationController
* before_action :set_user
* after_action :log_request
* around_action :trace_request
*
* def index
* @posts = @user.posts.all
* end
*
* private
*
* def set_user
* @user = User.find(session[:user_id])
* end
*
* def log_request
* Logger.info(request.path)
* end
*
* def trace_request
* start = Time.now
* yield
* Logger.info("Request took #{Time.now = start} seconds")
* end
* end
* ```
*/
private class Filter extends StringlikeLiteralCfgNode {
private FilterCall call;
private FilterKind kind;
Filter() {
this = call.getFilterArgument() and
kind = call.getKind() and
call.getMethodName() = ["", "prepend_", "append_"] + kind + "_action"
}
predicate isPrepended() { call.getMethodName().regexpMatch("^prepend.+$") }
MethodCallCfgNode getCall() { result = call }
FilterKind getKind() { result = kind }
private ModuleBase getEnclosingModule() { result = call.getExpr().getEnclosingModule() }
/**
* Holds if this callback is registered before `other`. This does not
* guarantee that the callback will be executed before `other`. For example,
* `after_action` callbacks are executed in reverse order.
*/
predicate registeredBefore(Filter other) {
// before_action :this, :other
//
// before_action :this
// before_action :other
this.getBasicBlock() = other.getBasicBlock() and this.getASuccessor+() = other
or
this.getEnclosingModule() = other.getEnclosingModule() and
this.getBasicBlock().strictlyDominates(other.getBasicBlock()) and
this != other
or
// This callback is in a superclass of `other`'s class.
//
// class A
// before_action :this
//
// class B < A
// before_action :other
other.getEnclosingModule().getModule() = this.getEnclosingModule().getModule().getASubClass+()
}
/**
* Holds if this callback runs before `other`.
*/
private predicate runsBefore(Filter other, ActionControllerActionMethod action) {
other.getKind() = this.getKind() and
not this.skipped(action) and
not other.skipped(action) and
action = this.getAction() and
action = other.getAction() and
(
not this.isPrepended() and
(
not other.isPrepended() and
(
this.getKind() = TBeforeKind() and
this.registeredBefore(other)
or
this.getKind() = TAfterKind() and
other.registeredBefore(this)
)
or
other.isPrepended() and this.getKind() = TAfterKind()
)
or
this.isPrepended() and
(
not other.isPrepended() and
this.getKind() = TBeforeKind()
or
other.isPrepended() and
(
this.getKind() = TBeforeKind() and this.registeredBefore(other)
or
this.getKind() = TAfterKind() and other.registeredBefore(this)
)
)
)
}
Filter getNextFilter(ActionControllerActionMethod action) {
result != this and
this.runsBefore(result, action) and
not exists(Filter mid | this.runsBefore(mid, action) | mid.runsBefore(result, action))
}
predicate skipped(ActionControllerActionMethod action) {
this = any(SkipFilter f | f.getKind() = this.getKind()).getSkippedFilter(action)
}
private string getFilterName() { result = this.getConstantValue().getStringlikeValue() }
Callable getFilterCallable() { result = call.getFilterCallable(this.getFilterName()) }
ActionControllerActionMethod getAction() { result = call.getAction() }
}
private class BeforeFilter extends Filter {
BeforeFilter() { this.getKind() = TBeforeKind() }
}
private class AfterFilter extends Filter {
AfterFilter() { this.getKind() = TAfterKind() }
}
/**
* A call to `skip_before_action`, `skip_after_action` or `skip_around_action`.
* This skips a previously registered callback.
* Like other filter calls, the `except` and `only` keyword arguments can be
* passed to restrict the actions that the callback is skipped for.
*/
private class SkipFilter extends StringlikeLiteralCfgNode {
private FilterCall call;
private FilterKind kind;
SkipFilter() {
this = call.getFilterArgument() and
call.getMethodName() = "skip_" + kind + "_action"
}
FilterKind getKind() { result = kind }
private string getFilterName() { result = this.getConstantValue().getStringlikeValue() }
Callable getFilterCallable() { result = call.getFilterCallable(this.getFilterName()) }
ActionControllerActionMethod getAction() { result = call.getAction() }
Filter getSkippedFilter(ActionControllerActionMethod action) {
not result instanceof SkipFilter and
action = this.getAction() and
action = result.getAction() and
result.getFilterCallable() = this.getFilterCallable()
}
}
/**
* Holds if `pred` is called before `succ` in the callback chain for action `action`.
* `pred` and `succ` may be methods bound to callbacks or controller actions.
*/
predicate next(ActionControllerActionMethod action, Method pred, Method succ) {
exists(BeforeFilter f | pred = f.getFilterCallable() |
// Non-terminal before filter
succ = f.getNextFilter(action).getFilterCallable()
or
// Final before filter
not exists(f.getNextFilter(action)) and
not f.skipped(action) and
action = f.getAction() and
succ = action
)
or
exists(AfterFilter f |
// First after filter
action = f.getAction() and
not f.skipped(action) and
pred = action and
succ = f.getFilterCallable() and
not exists(AfterFilter g | g.getNextFilter(action) = f)
or
// Subsequent after filter
pred = f.getFilterCallable() and
succ = f.getNextFilter(action).getFilterCallable()
)
}
/**
* Holds if `pred` is called before `succ` in the callback chain for some action.
* `pred` and `succ` may be methods bound to callbacks or controller actions.
*/
cached
predicate next(Method pred, Method succ) {
exists(ActionControllerActionMethod action | next(action, pred, succ))
}
}

View File

@@ -1,4 +1,46 @@
actionDispatchRoutes
| action_controller/routes.rb:2:5:2:20 | call to resources | delete | users/:id | users | destroy |
| action_controller/routes.rb:2:5:2:20 | call to resources | get | users | users | index |
| action_controller/routes.rb:2:5:2:20 | call to resources | get | users/:id | users | show |
| action_controller/routes.rb:2:5:2:20 | call to resources | get | users/new | users | new |
| action_controller/routes.rb:2:5:2:20 | call to resources | get | users:id/edit | users | edit |
| action_controller/routes.rb:2:5:2:20 | call to resources | patch | users/:id | users | update |
| action_controller/routes.rb:2:5:2:20 | call to resources | post | users | users | create |
| action_controller/routes.rb:2:5:2:20 | call to resources | put | users/:id | users | update |
| action_controller/routes.rb:3:5:5:7 | call to resources | delete | comments/:id | comments | destroy |
| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments | comments | index |
| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments/:id | comments | show |
| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments/new | comments | new |
| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments:id/edit | comments | edit |
| action_controller/routes.rb:3:5:5:7 | call to resources | patch | comments/:id | comments | update |
| action_controller/routes.rb:3:5:5:7 | call to resources | post | comments | comments | create |
| action_controller/routes.rb:3:5:5:7 | call to resources | put | comments/:id | comments | update |
| action_controller/routes.rb:4:9:4:32 | call to get | get | comments/:comment_id/photo | comments | photo |
| action_controller/routes.rb:6:5:6:21 | call to resources | delete | photos/:id | photos | destroy |
| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos | photos | index |
| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos/:id | photos | show |
| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos/new | photos | new |
| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos:id/edit | photos | edit |
| action_controller/routes.rb:6:5:6:21 | call to resources | patch | photos/:id | photos | update |
| action_controller/routes.rb:6:5:6:21 | call to resources | post | photos | photos | create |
| action_controller/routes.rb:6:5:6:21 | call to resources | put | photos/:id | photos | update |
| action_controller/routes.rb:7:5:9:7 | call to resources | delete | posts/:id | posts | destroy |
| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts | posts | index |
| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts/:id | posts | show |
| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts/new | posts | new |
| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts:id/edit | posts | edit |
| action_controller/routes.rb:7:5:9:7 | call to resources | patch | posts/:id | posts | update |
| action_controller/routes.rb:7:5:9:7 | call to resources | post | posts | posts | create |
| action_controller/routes.rb:7:5:9:7 | call to resources | put | posts/:id | posts | update |
| action_controller/routes.rb:8:9:8:34 | call to post | post | posts/:post_id/upvote | posts | upvote |
| action_controller/routes.rb:10:5:10:19 | call to resources | delete | tags/:id | tags | destroy |
| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags | tags | index |
| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags/:id | tags | show |
| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags/new | tags | new |
| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags:id/edit | tags | edit |
| action_controller/routes.rb:10:5:10:19 | call to resources | patch | tags/:id | tags | update |
| action_controller/routes.rb:10:5:10:19 | call to resources | post | tags | tags | create |
| action_controller/routes.rb:10:5:10:19 | call to resources | put | tags/:id | tags | update |
| app/config/routes.rb:2:3:8:5 | call to resources | get | posts | posts | index |
| app/config/routes.rb:2:3:8:5 | call to resources | get | posts/:id | posts | show |
| app/config/routes.rb:3:5:6:7 | call to resources | delete | posts/:post_id/comments/:id | comments | destroy |
@@ -34,24 +76,42 @@ actionDispatchRoutes
| app/config/routes.rb:49:5:49:95 | call to delete | delete | users/:user/notifications | users/notifications | destroy |
| app/config/routes.rb:50:5:50:94 | call to post | post | users/:user/notifications/:notification_id/mark_as_read | users/notifications | mark_as_read |
actionDispatchControllerMethods
| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:2:3:3:5 | index |
| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:5:3:6:5 | show |
| action_controller/routes.rb:2:5:2:20 | call to resources | action_controller/input_access.rb:2:3:49:5 | index |
| action_controller/routes.rb:2:5:2:20 | call to resources | action_controller/logging.rb:2:5:8:7 | index |
| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:12:3:46:5 | index |
| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:48:3:49:5 | create |
| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:51:3:57:5 | show |
| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:63:3:65:5 | destroy |
| action_controller/routes.rb:3:5:5:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index |
| action_controller/routes.rb:3:5:5:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show |
| action_controller/routes.rb:4:9:4:32 | call to get | action_controller/controllers/comments_controller.rb:59:3:61:5 | photo |
| action_controller/routes.rb:6:5:6:21 | call to resources | action_controller/controllers/photos_controller.rb:3:3:6:5 | show |
| action_controller/routes.rb:6:5:6:21 | call to resources | app/controllers/photos_controller.rb:2:3:3:5 | show |
| action_controller/routes.rb:7:5:9:7 | call to resources | action_controller/controllers/posts_controller.rb:6:3:7:5 | index |
| action_controller/routes.rb:7:5:9:7 | call to resources | action_controller/controllers/posts_controller.rb:9:3:10:5 | show |
| action_controller/routes.rb:7:5:9:7 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index |
| action_controller/routes.rb:7:5:9:7 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show |
| action_controller/routes.rb:8:9:8:34 | call to post | action_controller/controllers/posts_controller.rb:12:3:13:5 | upvote |
| action_controller/routes.rb:8:9:8:34 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote |
| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:6:3:7:5 | index |
| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:9:3:10:5 | show |
| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index |
| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:2:3:36:5 | index |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:38:3:44:5 | show |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:50:3:52:5 | destroy |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:12:3:46:5 | index |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:48:3:49:5 | create |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:51:3:57:5 | show |
| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:63:3:65:5 | destroy |
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index |
| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show |
| app/config/routes.rb:7:5:7:37 | call to post | action_controller/controllers/posts_controller.rb:8:3:9:5 | upvote |
| app/config/routes.rb:7:5:7:37 | call to post | action_controller/controllers/posts_controller.rb:12:3:13:5 | upvote |
| app/config/routes.rb:7:5:7:37 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote |
| app/config/routes.rb:27:3:27:48 | call to match | action_controller/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:27:3:27:48 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show |
| app/config/routes.rb:27:3:27:48 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:28:3:28:50 | call to match | action_controller/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:28:3:28:50 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show |
| app/config/routes.rb:28:3:28:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:29:3:29:69 | call to match | action_controller/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:29:3:29:69 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show |
| app/config/routes.rb:29:3:29:69 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:30:3:30:50 | call to match | action_controller/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:30:3:30:50 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show |
| app/config/routes.rb:30:3:30:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show |
| app/config/routes.rb:50:5:50:94 | call to post | action_controller/controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read |
| app/config/routes.rb:50:5:50:94 | call to post | app/controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read |

View File

@@ -9,7 +9,8 @@ rawCalls
| app/views/foo/bars/show.html.erb:5:5:5:21 | call to raw |
| app/views/foo/bars/show.html.erb:7:5:7:19 | call to raw |
renderCalls
| action_controller/controllers/comments_controller.rb:42:21:42:64 | call to render |
| action_controller/controllers/comments_controller.rb:55:21:55:64 | call to render |
| action_controller/controllers/comments_controller.rb:71:5:71:68 | call to render |
| action_controller/controllers/foo/bars_controller.rb:6:5:6:37 | call to render |
| action_controller/controllers/foo/bars_controller.rb:23:5:23:76 | call to render |
| action_controller/controllers/foo/bars_controller.rb:35:5:35:33 | call to render |
@@ -29,9 +30,9 @@ renderToCalls
linkToCalls
| app/views/foo/bars/show.html.erb:33:5:33:41 | call to link_to |
httpResponses
| action_controller/controllers/comments_controller.rb:11:5:11:17 | call to body= | action_controller/controllers/comments_controller.rb:11:21:11:34 | ... = ... | text/http |
| action_controller/controllers/comments_controller.rb:21:5:21:37 | call to send_file | action_controller/controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" | application/octet-stream |
| action_controller/controllers/comments_controller.rb:47:5:47:20 | call to send_data | action_controller/controllers/comments_controller.rb:47:15:47:20 | @photo | application/octet-stream |
| action_controller/controllers/comments_controller.rb:21:5:21:17 | call to body= | action_controller/controllers/comments_controller.rb:21:21:21:34 | ... = ... | text/http |
| action_controller/controllers/comments_controller.rb:31:5:31:37 | call to send_file | action_controller/controllers/comments_controller.rb:31:24:31:36 | "my-file.ext" | application/octet-stream |
| action_controller/controllers/comments_controller.rb:60:5:60:20 | call to send_data | action_controller/controllers/comments_controller.rb:60:15:60:20 | @photo | application/octet-stream |
| action_controller/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | action_controller/controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" | text/html |
| action_controller/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | action_controller/controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" | text/html |
| action_controller/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | action_controller/controllers/foo/bars_controller.rb:35:18:35:33 | call to [] | application/json |

View File

@@ -1,28 +1,31 @@
actionControllerControllerClasses
| controllers/comments_controller.rb:1:1:53:3 | CommentsController |
| controllers/application_controller.rb:1:1:13:3 | ApplicationController |
| controllers/comments_controller.rb:1:1:95:3 | CommentsController |
| controllers/foo/bars_controller.rb:3:1:46:3 | BarsController |
| controllers/photos_controller.rb:1:1:4:3 | PhotosController |
| controllers/posts_controller.rb:1:1:10:3 | PostsController |
| controllers/photos_controller.rb:1:1:10:3 | PhotosController |
| controllers/posts_controller.rb:1:1:24:3 | PostsController |
| controllers/tags_controller.rb:1:1:2:3 | TagsController |
| controllers/users/notifications_controller.rb:2:3:5:5 | Users::NotificationsController |
| input_access.rb:1:1:50:3 | UsersController |
| params_flow.rb:1:1:162:3 | MyController |
| params_flow.rb:170:1:178:3 | Subclass |
actionControllerActionMethods
| controllers/comments_controller.rb:2:3:36:5 | index |
| controllers/comments_controller.rb:38:3:44:5 | show |
| controllers/comments_controller.rb:46:3:48:5 | photo |
| controllers/comments_controller.rb:50:3:52:5 | destroy |
| controllers/comments_controller.rb:12:3:46:5 | index |
| controllers/comments_controller.rb:48:3:49:5 | create |
| controllers/comments_controller.rb:51:3:57:5 | show |
| controllers/comments_controller.rb:59:3:61:5 | photo |
| controllers/comments_controller.rb:63:3:65:5 | destroy |
| controllers/foo/bars_controller.rb:5:3:7:5 | index |
| controllers/foo/bars_controller.rb:9:3:18:5 | show_debug |
| controllers/foo/bars_controller.rb:20:3:24:5 | show |
| controllers/foo/bars_controller.rb:26:3:28:5 | go_back |
| controllers/foo/bars_controller.rb:30:3:32:5 | go_back_2 |
| controllers/foo/bars_controller.rb:34:3:39:5 | show_2 |
| controllers/photos_controller.rb:2:3:3:5 | show |
| controllers/posts_controller.rb:2:3:3:5 | index |
| controllers/posts_controller.rb:5:3:6:5 | show |
| controllers/posts_controller.rb:8:3:9:5 | upvote |
| controllers/photos_controller.rb:3:3:6:5 | show |
| controllers/photos_controller.rb:8:3:9:5 | foo |
| controllers/posts_controller.rb:6:3:7:5 | index |
| controllers/posts_controller.rb:9:3:10:5 | show |
| controllers/posts_controller.rb:12:3:13:5 | upvote |
| controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read |
| input_access.rb:2:3:49:5 | index |
| logging.rb:2:5:8:7 | index |
@@ -63,10 +66,12 @@ actionControllerActionMethods
| params_flow.rb:165:3:167:5 | m34 |
| params_flow.rb:171:3:173:5 | m35 |
paramsCalls
| controllers/comments_controller.rb:75:36:75:41 | call to params |
| controllers/foo/bars_controller.rb:13:21:13:26 | call to params |
| controllers/foo/bars_controller.rb:14:10:14:15 | call to params |
| controllers/foo/bars_controller.rb:21:21:21:26 | call to params |
| controllers/foo/bars_controller.rb:22:10:22:15 | call to params |
| controllers/posts_controller.rb:18:23:18:28 | call to params |
| params_flow.rb:3:10:3:15 | call to params |
| params_flow.rb:7:10:7:15 | call to params |
| params_flow.rb:11:10:11:15 | call to params |
@@ -116,10 +121,12 @@ paramsCalls
| params_flow.rb:172:10:172:15 | call to params |
| params_flow.rb:176:10:176:15 | call to params |
paramsSources
| controllers/comments_controller.rb:75:36:75:41 | call to params |
| controllers/foo/bars_controller.rb:13:21:13:26 | call to params |
| controllers/foo/bars_controller.rb:14:10:14:15 | call to params |
| controllers/foo/bars_controller.rb:21:21:21:26 | call to params |
| controllers/foo/bars_controller.rb:22:10:22:15 | call to params |
| controllers/posts_controller.rb:18:23:18:28 | call to params |
| params_flow.rb:3:10:3:15 | call to params |
| params_flow.rb:7:10:7:15 | call to params |
| params_flow.rb:11:10:11:15 | call to params |
@@ -169,19 +176,22 @@ paramsSources
| params_flow.rb:172:10:172:15 | call to params |
| params_flow.rb:176:10:176:15 | call to params |
httpInputAccesses
| controllers/comments_controller.rb:3:5:3:18 | call to params | ActionDispatch::Request#params |
| controllers/comments_controller.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters |
| controllers/comments_controller.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET |
| controllers/comments_controller.rb:6:5:6:16 | call to POST | ActionDispatch::Request#POST |
| controllers/comments_controller.rb:7:5:7:28 | call to query_parameters | ActionDispatch::Request#query_parameters |
| controllers/comments_controller.rb:8:5:8:30 | call to request_parameters | ActionDispatch::Request#request_parameters |
| controllers/comments_controller.rb:9:5:9:31 | call to filtered_parameters | ActionDispatch::Request#filtered_parameters |
| controllers/comments_controller.rb:51:12:51:30 | call to body_stream | ActionDispatch::Request#body_stream |
| controllers/application_controller.rb:11:53:11:64 | call to path | ActionDispatch::Request#path |
| controllers/comments_controller.rb:13:5:13:18 | call to params | ActionDispatch::Request#params |
| controllers/comments_controller.rb:14:5:14:22 | call to parameters | ActionDispatch::Request#parameters |
| controllers/comments_controller.rb:15:5:15:15 | call to GET | ActionDispatch::Request#GET |
| controllers/comments_controller.rb:16:5:16:16 | call to POST | ActionDispatch::Request#POST |
| controllers/comments_controller.rb:17:5:17:28 | call to query_parameters | ActionDispatch::Request#query_parameters |
| controllers/comments_controller.rb:18:5:18:30 | call to request_parameters | ActionDispatch::Request#request_parameters |
| controllers/comments_controller.rb:19:5:19:31 | call to filtered_parameters | ActionDispatch::Request#filtered_parameters |
| controllers/comments_controller.rb:64:12:64:30 | call to body_stream | ActionDispatch::Request#body_stream |
| controllers/comments_controller.rb:75:36:75:41 | call to params | ActionController::Metal#params |
| controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies | ActionController::Metal#cookies |
| controllers/foo/bars_controller.rb:13:21:13:26 | call to params | ActionController::Metal#params |
| controllers/foo/bars_controller.rb:14:10:14:15 | call to params | ActionController::Metal#params |
| controllers/foo/bars_controller.rb:21:21:21:26 | call to params | ActionController::Metal#params |
| controllers/foo/bars_controller.rb:22:10:22:15 | call to params | ActionController::Metal#params |
| controllers/posts_controller.rb:18:23:18:28 | call to params | ActionController::Metal#params |
| input_access.rb:3:5:3:18 | call to params | ActionDispatch::Request#params |
| input_access.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters |
| input_access.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET |
@@ -275,21 +285,22 @@ cookiesCalls
cookiesSources
| controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies |
redirectToCalls
| controllers/comments_controller.rb:40:21:40:49 | call to redirect_to |
| controllers/comments_controller.rb:53:21:53:49 | call to redirect_to |
| controllers/foo/bars_controller.rb:17:5:17:30 | call to redirect_to |
| controllers/foo/bars_controller.rb:27:5:27:39 | call to redirect_back_or_to |
| controllers/foo/bars_controller.rb:31:5:31:56 | call to redirect_back |
renderCalls
| controllers/comments_controller.rb:42:21:42:64 | call to render |
| controllers/comments_controller.rb:55:21:55:64 | call to render |
| controllers/comments_controller.rb:71:5:71:68 | call to render |
| controllers/foo/bars_controller.rb:6:5:6:37 | call to render |
| controllers/foo/bars_controller.rb:23:5:23:76 | call to render |
| controllers/foo/bars_controller.rb:35:5:35:33 | call to render |
| controllers/foo/bars_controller.rb:38:5:38:50 | call to render |
| controllers/foo/bars_controller.rb:44:5:44:17 | call to render |
httpResponses
| controllers/comments_controller.rb:11:5:11:17 | call to body= | controllers/comments_controller.rb:11:21:11:34 | ... = ... |
| controllers/comments_controller.rb:21:5:21:37 | call to send_file | controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" |
| controllers/comments_controller.rb:47:5:47:20 | call to send_data | controllers/comments_controller.rb:47:15:47:20 | @photo |
| controllers/comments_controller.rb:21:5:21:17 | call to body= | controllers/comments_controller.rb:21:21:21:34 | ... = ... |
| controllers/comments_controller.rb:31:5:31:37 | call to send_file | controllers/comments_controller.rb:31:24:31:36 | "my-file.ext" |
| controllers/comments_controller.rb:60:5:60:20 | call to send_data | controllers/comments_controller.rb:60:15:60:20 | @photo |
| controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" |
| controllers/foo/bars_controller.rb:23:5:23:76 | call to render | controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" |
| controllers/foo/bars_controller.rb:35:5:35:33 | call to render | controllers/foo/bars_controller.rb:35:18:35:33 | call to [] |
@@ -300,21 +311,21 @@ actionControllerHelperMethods
getAssociatedControllerClasses
controllerTemplateFiles
headerWriteAccesses
| controllers/comments_controller.rb:15:5:15:35 | call to []= | content-type | controllers/comments_controller.rb:15:39:15:49 | ... = ... |
| controllers/comments_controller.rb:16:5:16:46 | call to set_header | content-length | controllers/comments_controller.rb:16:43:16:45 | 100 |
| controllers/comments_controller.rb:17:5:17:39 | call to []= | x-custom-header | controllers/comments_controller.rb:17:43:17:46 | ... = ... |
| controllers/comments_controller.rb:18:5:18:39 | call to []= | x-another-custom-header | controllers/comments_controller.rb:18:43:18:47 | ... = ... |
| controllers/comments_controller.rb:19:5:19:49 | call to add_header | x-yet-another | controllers/comments_controller.rb:19:42:19:49 | "indeed" |
| controllers/comments_controller.rb:25:5:25:21 | call to location= | location | controllers/comments_controller.rb:25:25:25:36 | ... = ... |
| controllers/comments_controller.rb:26:5:26:26 | call to cache_control= | cache-control | controllers/comments_controller.rb:26:30:26:36 | ... = ... |
| controllers/comments_controller.rb:27:5:27:27 | call to _cache_control= | cache-control | controllers/comments_controller.rb:27:31:27:37 | ... = ... |
| controllers/comments_controller.rb:28:5:28:17 | call to etag= | etag | controllers/comments_controller.rb:28:21:28:27 | ... = ... |
| controllers/comments_controller.rb:29:5:29:20 | call to charset= | content-type | controllers/comments_controller.rb:29:24:29:30 | ... = ... |
| controllers/comments_controller.rb:30:5:30:25 | call to content_type= | content-type | controllers/comments_controller.rb:30:29:30:35 | ... = ... |
| controllers/comments_controller.rb:32:5:32:17 | call to date= | date | controllers/comments_controller.rb:32:21:32:30 | ... = ... |
| controllers/comments_controller.rb:33:5:33:26 | call to last_modified= | last-modified | controllers/comments_controller.rb:33:30:33:43 | ... = ... |
| controllers/comments_controller.rb:34:5:34:22 | call to weak_etag= | etag | controllers/comments_controller.rb:34:26:34:32 | ... = ... |
| controllers/comments_controller.rb:35:5:35:24 | call to strong_etag= | etag | controllers/comments_controller.rb:35:28:35:34 | ... = ... |
| controllers/comments_controller.rb:25:5:25:35 | call to []= | content-type | controllers/comments_controller.rb:25:39:25:49 | ... = ... |
| controllers/comments_controller.rb:26:5:26:46 | call to set_header | content-length | controllers/comments_controller.rb:26:43:26:45 | 100 |
| controllers/comments_controller.rb:27:5:27:39 | call to []= | x-custom-header | controllers/comments_controller.rb:27:43:27:46 | ... = ... |
| controllers/comments_controller.rb:28:5:28:39 | call to []= | x-another-custom-header | controllers/comments_controller.rb:28:43:28:47 | ... = ... |
| controllers/comments_controller.rb:29:5:29:49 | call to add_header | x-yet-another | controllers/comments_controller.rb:29:42:29:49 | "indeed" |
| controllers/comments_controller.rb:35:5:35:21 | call to location= | location | controllers/comments_controller.rb:35:25:35:36 | ... = ... |
| controllers/comments_controller.rb:36:5:36:26 | call to cache_control= | cache-control | controllers/comments_controller.rb:36:30:36:36 | ... = ... |
| controllers/comments_controller.rb:37:5:37:27 | call to _cache_control= | cache-control | controllers/comments_controller.rb:37:31:37:37 | ... = ... |
| controllers/comments_controller.rb:38:5:38:17 | call to etag= | etag | controllers/comments_controller.rb:38:21:38:27 | ... = ... |
| controllers/comments_controller.rb:39:5:39:20 | call to charset= | content-type | controllers/comments_controller.rb:39:24:39:30 | ... = ... |
| controllers/comments_controller.rb:40:5:40:25 | call to content_type= | content-type | controllers/comments_controller.rb:40:29:40:35 | ... = ... |
| controllers/comments_controller.rb:42:5:42:17 | call to date= | date | controllers/comments_controller.rb:42:21:42:30 | ... = ... |
| controllers/comments_controller.rb:43:5:43:26 | call to last_modified= | last-modified | controllers/comments_controller.rb:43:30:43:43 | ... = ... |
| controllers/comments_controller.rb:44:5:44:22 | call to weak_etag= | etag | controllers/comments_controller.rb:44:26:44:32 | ... = ... |
| controllers/comments_controller.rb:45:5:45:24 | call to strong_etag= | etag | controllers/comments_controller.rb:45:28:45:34 | ... = ... |
loggingCalls
| logging.rb:3:9:3:31 | call to info | logging.rb:3:21:3:31 | "some info" |
| logging.rb:4:9:4:31 | call to warn | logging.rb:4:21:4:31 | "a warning" |

View File

@@ -0,0 +1,48 @@
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/comments_controller.rb:90:3:91:5 | foo |
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/comments_controller.rb:12:3:46:5 | index | controllers/comments_controller.rb:86:3:88:5 | this_must_run_last |
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/comments_controller.rb:82:3:84:5 | this_must_run_first | controllers/application_controller.rb:10:3:12:5 | log_request |
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/comments_controller.rb:90:3:91:5 | foo | controllers/comments_controller.rb:93:3:94:5 | bar |
| controllers/comments_controller.rb:12:3:46:5 | index | controllers/comments_controller.rb:93:3:94:5 | bar | controllers/comments_controller.rb:12:3:46:5 | index |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/comments_controller.rb:69:3:72:5 | ensure_user_can_edit_comments |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:78:3:80:5 | log_comment_change |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:69:3:72:5 | ensure_user_can_edit_comments | controllers/comments_controller.rb:90:3:91:5 | foo |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:78:3:80:5 | log_comment_change | controllers/comments_controller.rb:86:3:88:5 | this_must_run_last |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:82:3:84:5 | this_must_run_first | controllers/application_controller.rb:10:3:12:5 | log_request |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:90:3:91:5 | foo | controllers/comments_controller.rb:93:3:94:5 | bar |
| controllers/comments_controller.rb:48:3:49:5 | create | controllers/comments_controller.rb:93:3:94:5 | bar | controllers/comments_controller.rb:48:3:49:5 | create |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/comments_controller.rb:74:3:76:5 | set_comment |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:86:3:88:5 | this_must_run_last |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:74:3:76:5 | set_comment | controllers/comments_controller.rb:90:3:91:5 | foo |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:82:3:84:5 | this_must_run_first | controllers/application_controller.rb:10:3:12:5 | log_request |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:90:3:91:5 | foo | controllers/comments_controller.rb:93:3:94:5 | bar |
| controllers/comments_controller.rb:51:3:57:5 | show | controllers/comments_controller.rb:93:3:94:5 | bar | controllers/comments_controller.rb:51:3:57:5 | show |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/comments_controller.rb:90:3:91:5 | foo |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:78:3:80:5 | log_comment_change |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:78:3:80:5 | log_comment_change | controllers/comments_controller.rb:86:3:88:5 | this_must_run_last |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:82:3:84:5 | this_must_run_first | controllers/application_controller.rb:10:3:12:5 | log_request |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:90:3:91:5 | foo | controllers/comments_controller.rb:93:3:94:5 | bar |
| controllers/comments_controller.rb:59:3:61:5 | photo | controllers/comments_controller.rb:93:3:94:5 | bar | controllers/comments_controller.rb:59:3:61:5 | photo |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/comments_controller.rb:69:3:72:5 | ensure_user_can_edit_comments |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:78:3:80:5 | log_comment_change |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:69:3:72:5 | ensure_user_can_edit_comments | controllers/comments_controller.rb:74:3:76:5 | set_comment |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:74:3:76:5 | set_comment | controllers/comments_controller.rb:90:3:91:5 | foo |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:78:3:80:5 | log_comment_change | controllers/comments_controller.rb:86:3:88:5 | this_must_run_last |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:82:3:84:5 | this_must_run_first | controllers/application_controller.rb:10:3:12:5 | log_request |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:90:3:91:5 | foo | controllers/comments_controller.rb:93:3:94:5 | bar |
| controllers/comments_controller.rb:63:3:65:5 | destroy | controllers/comments_controller.rb:93:3:94:5 | bar | controllers/comments_controller.rb:63:3:65:5 | destroy |
| controllers/photos_controller.rb:3:3:6:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/photos_controller.rb:3:3:6:5 | show |
| controllers/photos_controller.rb:3:3:6:5 | show | controllers/photos_controller.rb:3:3:6:5 | show | controllers/photos_controller.rb:8:3:9:5 | foo |
| controllers/posts_controller.rb:6:3:7:5 | index | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:6:3:7:5 | index |
| controllers/posts_controller.rb:6:3:7:5 | index | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/posts_controller.rb:9:3:10:5 | show | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:17:3:19:5 | set_post |
| controllers/posts_controller.rb:9:3:10:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/posts_controller.rb:9:3:10:5 | show | controllers/posts_controller.rb:17:3:19:5 | set_post | controllers/posts_controller.rb:9:3:10:5 | show |
| controllers/posts_controller.rb:12:3:13:5 | upvote | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:17:3:19:5 | set_post |
| controllers/posts_controller.rb:12:3:13:5 | upvote | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user |
| controllers/posts_controller.rb:12:3:13:5 | upvote | controllers/posts_controller.rb:12:3:13:5 | upvote | controllers/posts_controller.rb:21:3:23:5 | log_upvote |
| controllers/posts_controller.rb:12:3:13:5 | upvote | controllers/posts_controller.rb:17:3:19:5 | set_post | controllers/posts_controller.rb:12:3:13:5 | upvote |

View File

@@ -0,0 +1,5 @@
private import codeql.ruby.AST
private import codeql.ruby.frameworks.ActionController
private import codeql.ruby.DataFlow
query predicate filterChain = ActionController::Filters::next/3;

View File

@@ -0,0 +1,13 @@
class ApplicationController < ActionController::Base
before_action :log_request
private
def set_user
@user = User.find(session[:user_id])
end
def log_request
Rails.logger.info("Request: #{request.method} #{request.path}")
end
end

View File

@@ -1,4 +1,14 @@
class CommentsController < ApplicationController
prepend_after_action :this_must_run_last
before_action :set_user
before_action :ensure_user_can_edit_comments, only: WRITE_ACTIONS
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :foo, :bar
after_action :log_comment_change, except: [:index, :show, :new]
prepend_before_action :this_must_run_first
WRITE_ACTIONS = %i[create update destroy]
def index
request.params
request.parameters
@@ -35,6 +45,9 @@ class CommentsController < ApplicationController
response.strong_etag = "value"
end
def create
end
def show
respond_to do |format|
format.html { redirect_to(comment_view_url) }
@@ -50,4 +63,33 @@ class CommentsController < ApplicationController
def destroy
body = request.body_stream
end
private
def ensure_user_can_edit_comments
return if @user.can_edit_comments?
render status: 403, text: "You are not allowed to edit comments"
end
def set_comment
@comment = @user.comments.find(params[:id])
end
def log_comment_change
AuditLog.create!(:comment_change, user: @user, comment: @comment)
end
def this_must_run_first
# for whatever reason
end
def this_must_run_last
# for whatever reason
end
def foo
end
def bar
end
end

View File

@@ -1,4 +1,10 @@
class PhotosController < ApplicationController
after_action :foo
def show
@a = 1
@b = 2
end
def foo
end
end

View File

@@ -1,4 +1,8 @@
class PostsController < ApplicationController
before_action :set_user
append_before_action :set_post, only: [:show, :upvote]
after_action :log_upvote, only: :upvote
def index
end
@@ -7,4 +11,14 @@ class PostsController < ApplicationController
def upvote
end
end
private
def set_post
@post = Post.find(params[:id])
end
def log_upvote
Rails.logger.info("Post upvoted: #{@post.id}")
end
end

View File

@@ -0,0 +1,11 @@
Rails.application.routes.draw do
resources :users
resources :comments do
get "photo", on: :member
end
resources :photos
resources :posts do
post "upvote", on: :member
end
resources :tags
end