I'm looking to load a single (chosen randomly) object from a single table in my database on every page of my rails app.
For example, a quotes table which has several quotes in the table, and I just want one on every page load.
What's the best way to accomplish this? Obviously copy & pasting the query into each controller isn't the right way to go about this.
I wouldn't use before_filter for this, there is no need to access database on redirecting actions and other "not rendered" actions. Instead I would use helper_function, and I would call it in the layout, as you need to position it anyways.
def random_quote
#quote ||= "Select random quote here"
end
helper_method :random_quote
Your method of selecting a quote is up to you. You just need to access random_quote as a normal helper method in the layout. This only access one quote per action, only if the layout is rendered.
This kind of stuff typically goes into a before_filter in the ApplicationController :
before_filter :get_random_quote
#This code is executed before every action of your app
def get_random_quote
random_id = ...#Generate a random ID ...
#random_quote = Quote.find(random_id)
end
Then in your views, just refer to #random_quote. Done!
Edit : on second thought, Matzi solution seems smarter. The request will only get called when you actually output something. Nothing's wasted.
Assuming PostgreSQL:
before_filter :get_quote
def get_quote
#quote = Quote.order('RANDOM()').limit(1)
end
Related
I have an application that collect user input and store to DB and show back to user.
One user entered "alert(1)" into the name field and saved it into DB.
Whenever the name is displayed, the page will be broken.
I know how to fix that input only with validation for input, and h() for output.
However, I have so many input fields and so many outputs that accept users' text.
Is there any simple way to prevent this happening(i.e. overriding params method, etc)?
I also want to know how you expert guys are dealing with this problem?
As of Rails 3, my understanding was that embedded ruby code was html escaped by default. You don't need to use h() to make it that way. That is, if you use <%= "<script>a=1/0;</script>" %> in a view, the string is going to be made html safe, and so the script doesn't execute. You would have to specifically use raw() or something similar to avoid it - which you should naturally not do unless you're really confident about the contents.
For output, Rails 3 automatically html-encode all text unless I use raw() method.
For input, How about making a common validator and apply to all fields that are text or string? Is it desirable?
http://api.rubyonrails.org/classes/ActiveModel/Validator.html
class MyValidator < ActiveModel::Validator
def validate(record)
record.class.columns.each do |c|
if c.type==:text || c.type == :string
record.errors.add c.type, "script tag is not allowed" if c[/<script[^>]*>/]
end
end
end
end
Currently my URL's appear as www.website.com/entries/1, I'd like to make them appear as www.website.com/title-of-entry. I've been messing around with routes and have been able to get the entry title to display in the URL, but Rails is unable to find the entry without supplying an ID. If I send the ID along with the parameters, the URL appears as www.website.com/title-of-entry?=1. Is there anyway I can pass the ID without having it appear in the URL as a parameter? Thanks!
Like most things, there's a gem for this.
FriendlyID.
Installation is easy and you'll be up and running in minutes. Give it a whirl.
Ususally you'll want to to save this part in the database title-of-entry (call the field slug or something`). Your model could look something like this:
class Entry < ActiveRecord::Base
before_validation :set_slug
def set_slug
self.slug = self.title.parameterize
end
def to_param
self.slug
end
end
Now your generated routes look like this: /entries/title-of-entry
To find the corresponding entries you'll have to change your controller:
# instad of this
#entry = Entry.find(params[:id]
# use this
#entry = Entry.find_by_slug(params[:id])
Update
A few things to bear in mind:
You'll have to make sure that slug is unique, otherwise Entry.find_by_slug(params[:id]) will always return the first entry with this slug it encounters.
Entry.find_by_slug(params[:id]) will not raise a ActiveRecord::RecordNotFound exception, but instead just return nil. Consider using Entry.find_by_slug!(params[:id]).
If you really want your routes to look like this /title-of-entry, you'll probably run into problems later on. The router might get you unexpected results if a entry slug looks the same as another controller's name.
I'm really new to programming, so I'm having trouble explaining this -- please forgive.
I have a Document model and a Note model in my rails app. A note belongs to a document, and a document has many notes -- the foreign key in the notes table is document_id.
On my document show page, I have a form for a note which uses a :content attribute as a text_area field.
What I'd like to do is pass the document's id into the note params so the note would have both the :content the user submits alng with the :document_id based on the document_path.
Currently I'm adding the :document_id into the note's params hash using a hidden_field form helper, and sending the whole thing to the NotesController, but I hope there's a cleaner / perhaps easier way.
If this makes sense, can someone suggest a better way to do this? Thank you.
In your routes have something like
resources :documents do
resources :notes
end
Then you should be adding a note via this route
/documents/5/notes/new
Then in your NotesController have
def create
#document = Document.find(params[:document_id])
#note = #document.notes.build(params[:note])
if #note.save
# Blah
else
# Blah
end
end
(In no way has this been tested - but it gives you an idea of how to do it in a RESTFUL style without hidden fields)
Imagine i have a blog, and i want a footer or sidebar displaying my 3 most recent posts at any given time.
What is the best way to do this?
I can call #recent_posts in every single controller to have them ready for the layout but this doesn't seem like the best way...at all...
#recent_posts = Posts.all(:limit => 3)
I've been fiddling around with partials, but they do need an instance variable carrying the #recent_posts.
There may be two parts to your concern: 1) performance, and 2) effort required. Both are easily addressed.
As Andrei S notes in his answer, the convenience/effort issue is mitigated by using a before_filter that calls the method that does the work from the ApplicationController class.
The performance issue is only slightly more work. Instead of the method being
def most_recent_posts
Posts.order(created_at DESC).limit(3)
end
instead do this
def most_recent_posts
#most_recent_posts ||= Posts.order(created_at DESC).limit(3)
end
which checks the instance variable for nil; if nil, it does the query and assigns the result to the instance variable.
You'll also need a way to update when a new post is added, so perhaps something like
def clear_most_recent_posts!
#most_recent_posts = nil
end
and then just call clear_most_recent_posts! from the method(s) that modify the table. The before_filter will do its work only when needed.
I am sure some more eloquent rubyist has a nicer way of doing this, but this is an idea.
You could put the part where you have your posts in a partial and use it in the general layout of your app.
To load them all in every controller you could do a before_filter in your ApplicationController in which you set your instance variable, which will be available in your partial that gets rendered in the layout
This way you only get to do it once, and it will get done everywhere (of course you could set conditions on the filter and the layout to load them when you need, that's if you don't really need them on every page)
I have an application with associations and will pagination the pages.
The index page from the main object "cat_list" shows links to the association "data_lists". The index page has also pagination with "will_paginate"
I show for example page=3 "/cat_lists?page=3"
I click the link of a "data_lists" for example "/cat_lists/8984/data_lists"
This index page shows a list of data_lists with Edit, Destroy and a New link.
And a Back Link to the cat_lists index page now "/cat_lists"
What is the best practice to implement the features, that the Back Link now the page from which comes from?
I usually record the history in the session and then call it via redirect_to back (no colon)
def index
... do your stuff ...
record_history
end
protected
def record_history
session[:history] ||= []
session[:history].push request.url
session[:history] = session[:history].last(10) # limit the size to 10
end
def back
session[:history].pop
end
Note that this only works for GET requests.
If I understand you correctly link_to('Back', :back) is what you want.
I also use mosch's approach.
link_to('Back', :back) only uses the browsers 'back' functionality. Managing the history server side gives you more control (i.e. if you've come from a google search, guess what happens on :back).
Managing the history server side gives you the possibility to hide links that would take the user off your page. Further you can offer the user to browse multiple steps back - i.e. via dropdown.