I do have a question concerning the development of a gem for Rails 3.
I would like to insert specific HTML snippets/partials/fragments (e.g. a form or an image on a fixed position) into every HTTP get response. I am wondering what technique would be the most appropriate for this use case. I see two solutions, but I am not sure which one will be the better approach.
Rack middleware loaded by a Rails engine: I could write a rack middleware that parses the response HTML document and insert my HTML snippets/partials before the closing body tag. This approach seems to be a little bit dirty, since the proper formatting of the response document is not guaranteed.
Inserting the snippet at the controller level: Maybe as an after_filter?! The problem here is that I somehow have to guarantee that my after_filter will be the last one in the filter chain.
I am curious whether there are further approaches and which one you would pick. It would be great to have access to the standard Rails view helpers from within the partial/snippet I am planning to insert into the response. By loading the gem the snippet should be automatically included into every response without requiring the user to insert a partial at the views.
Thanks in advance
Peter
Related
I have a search page where I update the URL params on the page as filters are added or removed by the user. This allows me to deep link into the page (ie. going to /search?location=new+york&time=afternoon will set the location and afternoon filters).
I also have a filter named format. I noticed that passing in ?format=whatevervalue to the URL and then reloading the page with that param causes Rails to return a Completed 406 Not Acceptable error. It seems that format is a reserved Rails URL parameter.
Is there anyway to unreserve this parameter name for a particular endpoint?
In the context of an URL in Ruby on Rails there are at least four reserved parameter names: controller, method, id, format.
You cannot use these keys for anything else than for their intended purpose.
If you try to you will override the value internally set by Rails. In your example by setting ?format=whatevervalue you override the default format (html) and your application will try to find and render a whatevervalue template instead of the html formatted template. This will obviously not work.
Fun fact: Instead of using the default Rails path format like /users/123/edit you could use query parameters instead like this: /?controller=users&id=123&method=edit&format&html.
My suggestion is: Do not try to fight Rails conventions. Whenever you try to work around basic Rails conventions it will hurt you later on because it makes updates more difficult, common gems might break, unexpected side-effects will happen. Just use another name for that parameter.
I'm not clear of when (or if) I should use multiple Grails encodeAsXXX calls.
This reference says you need to encodeAsURL and then encodeAsJavaScript: http://grailsrocks.com/blog/2013/4/19/can-i-pwn-your-grails-application
It also says you need to encodeAsURL and then encodeAsHTML, I don't understand why this is necessary in the case shown but not all the time?
Are there other cases I should me using multiple chained encoders?
If I'm rendering a URL to a HTML attribute should I encodeAsURL then encodeAsHTML?
If I'm rendering a URL to a JavaScript variable sent as part of a HTML document (via a SCRIPT element) should I encodeAsURL, encodeAsJavaScript then encodeAsHTML?
If I'm rendering a string to a JavaScript variable sent as part of a HTML document should I encodeAsJavaScript then encodeAsHTML?
The official docs - https://docs.grails.org/latest/guide/security.html - don't show any examples of multiple chained encoders.
I can't see how I can understand what to do here except by finding the source for all the encoders and looking at what they encode and what's valid on the receiving end - but I figure it shouldn't be that hard for a developer and there is probably something simple I'm missing or some instructions I haven't found.
FWIW, I think the encoders I'm talking about are these ones:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/JavaScriptUtils.html#javaScriptEscape-java.lang.String-
https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html#encode(java.lang.String,%20java.lang.String)
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/HtmlUtils.html#htmlEscape-java.lang.String-
.
It is certainly important to always consider XSS but in reading your question I think you are overestimating what you need to do. As long as you're using Grails 2.3 or higher and your grails.views.default.codec is set to html which it will be by default, everything rendered in your GSP with ${} will be escaped properly for you.
It is only when you are intentionally bypassing the escaping, such as if you need to get sanitized user input back into valid JavaScript within your GSP for some reason, that you would need to use the encodeAsXXX methods or similar.
I would argue (and the article makes a mention of this as well) that this should raise a smell anyway, as you probably should have that JavaScript encapsulated in a different file or TagLib where the escaping is handled.
Bottom line, use the encoding methods only if you are overriding the default HTML encoding, otherwise ${} handles it for you.
In Rails 4, how does one execute an arbitrary controller action and render the response to a string?
This is obviously a bad practice, but there are circumstances when it becomes very difficult to avoid:
You are making an offline copy or e-mail attachment of a dynamically rendered pdf (or any self-contained response).
Aforementioned response involves views and controllers not under your control, or in external gems.
Aforementioned views involve layouts and dozens of partials using relative paths and custom template rendering engines.
In some circumstances (when calling from another controller), it is possible to eliminate the dependency on the controller by replacing any data needed by the view. However, this typically still breaks the view rendering, as relative paths can no longer be passed to the render function within partials (among other issues).
So I haven't actually done this. Or anything like it.
But I remembered you can get a Rack app object for any arbitrary rails action. So it seemed like you could use that rack-compat interface to all an arbitrary action and get a response internally, without actually having to make an http request.
Googled around things I vaguely remembered to put the pieces together, and got this, which I have tried out in a very simple dummy app I made, and it seems to work:
rack_env = Rack::MockRequest.env_for("/some/url?foo=bar")
rack_app = SomeController.action(:index)
(status, headers, rack_body) = rack_app.call(rack_env)
str = rack_body.body
I was surprised to need to call #body on the thing I already thought was the body, not sure exactly what's going on I guess I don't entirely understand the rack api. Not sure if MockRequest is the right way to build a request. Not sure if there's a better way (but heck 3-4 lines ain't bad). But it does seem to work.
(There's probably a way to get the 'right' way to work too, with enough work -- there are for instance ways to change or add to the view template lookup paths, to put the original controller's views on the view lookup path, even when you're rendering the template from a new view. But I believe you that it gets painful, and am honestly not sure in this case what the 'right' way to do it is, I think the Rack method seems reasonable)
In my rails 4 app i want to add comments to my articles, but i want to add functional as most forum-engines do (like SMF), and i need to add bb-code for it.
Are there any good gem for it? With rails 4 support? How then in controller i can translate [quote] to some div with some style?
Also how is it good to store html data in database?
For example if i use haml, and somebody post comment as
- current_user.id
or something similar to this, how to secure my app from "bad boys" ? Sure i can change comments system to something like: quote_parent_id, but if i have multiple quotes in one comment? so it is hard to realise, better is to store html, but to secure it somehow.
Could i do this? And how? Please give good ideas, tutorials, gem-links.
Look into https://github.com/veger/ruby-bbcode
Since it converts to HTML and does not excecute user input as Ruby code - you'll be fairly safe. However, I havent tried the gem and its possible it introduces some XSS vulnerabilities.
Have you considered Markdown as an option?
You should also look into https://github.com/asceth/bbcoder ( I should note I am the original author ).
In the controller, changing a string such as "[quote=user]My post of epic importance[/quote]" into a div etc is just doing:
# assume params[:comment] is the text you are converting
params[:comment].bbcode_to_html
As for storing html in a database, there is no right or wrong answer. If you want to allow users to edit their posts later then I would lean towards not storing the html version but storing their original bbcode version. This way when you allow them to edit you aren't having to convert html back to bbcode.
To make sure you aren't open to XSS and other attacks I recommend combining other gems like sanitize.
Sanitize.clean(text.to_s).bbcode_to_html
Some more notes:
Multiple tags and nested tags are parsed as they are seen without any additional steps required. So a comment or post with lots of bbcode tags, multiple quotes, b tags or anything else is dealt with by just calling bbcode_to_html on the variable/string.
If a user tries to use haml in their post it should appear as-is. haml shouldn't try to eval the string unless you specifically tell it to which I'm not even sure how to do that unless haml as a special filter or operator.
In my rails 3 app, if I want a request to return json data does it matter if I use
mysite/show/1.js
or
mysite/show/1.json
I know it seems obvious to use the json version but in my responses they look the same to me.
First of all: It depends on the way you implement the respond_to block.
With 1.json it should be clear that it delivers data as JSON.
1.js could return Javascript that is evaluated by the page that requested it. In the early Rails/Ajax days this used to be done with RJS templates. See http://www.codyfauser.com/2005/11/20/rails-rjs-templates