I have a text_area form to create a quick Idea object. This form appears on many parts of the site so I move it as a shared/_idea_form.html.haml file.
I'm currently defining the new object in every controller action where the form is present with #ideas = Idea.new to make it work.
Is there a more convenient/global way define the #ideas = Idea.new outside each action? I.e. as a before_filter in the application controller. I'm not sure if that would be the right approach to this.
you can put it directly in view
<%= form_for #idea ||= Idea.new do |f| %>
#your text area
<%end%>
If you have it on most of the actions yes, that should be a good way. If was me in your place I think I would brake the rules and would do that in the partial... Sometimes rules dosen't make sense and this time is one of it. You just want a form on every page, and so you need to create always a new Idea for the form.. Or do that on the partial or just create the form without helpers.
Just one opinion :)
There are tons of options: using the decent_exposure gem (try it, it's cool!), using before_filters for setting the value of the #idea, manually creating new Idea in your form, defining some helper which will provide your form with a prepared Idea.
in app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
before_filter :create_new_idea
def create_new_idea
#idea = Idea.new
end
end
That will set #idea to a new object on every request. There must be some cases where you don't want #idea set to a new instance or even set at all. In that case there are a number of options, here's one:
class ApplicationController < ActionController::Base
before_filter :create_new_idea, lambda {|controller| controller.set_new_idea?}
def create_new_idea
#idea = Idea.new
end
def set_new_idea?
# this should be false in some case
end
end
Related
Say for example I have two models, posts and category. Now say I want to make it so the from the category show page you can create a new post using the form_for method. To do this, you will obviously need access to the #category variable and a new instance of a post (#post). Is this acceptable code in the controller?
#app/controllers/categories_controller.rb
def show
#category = Category.find(params[:id])
#post = Post.new
end
Or is it bad practice to have two instance variables defined in the one controller action - and if it is, what would be the best practice for a case like this?
I usually do something like:
#app/controllers/categories_controller.rb
helper_method :category
helper_method :post
def show
end
private
def category
#_category ||= params[:id] ? Category.find(params[:id]) : Category.new(params[:category])
end
def post
#_post ||= Post.new(params[:post])
end
Then, in your views, just refer to post or category (not #post or #_post). The nice thing is you can remove the same logic from your new, delete, etc methods...
Actions related to posts should be in the PostsController as much as possible.
Let's say the user is looking at all posts under the category "rails": /categories/rails
There's a button on that page to create a new post under the "rails" category, href: /posts/new?category=rails
This takes you to PostsController#new where you instantiate a new Post, validate the category param and build a view. This view could either be a new page, or a modal popping up.
Im working with a medium sized Rails application and I do this in every controller:
def create
#object = Model.new(params[:model].merge(editing_user: current_user))
...
end
def update
#object = Model.find(params[:id])
#object.editing_user = current_user
...
end
Setting the editing user over and over again is not DRY. I thought about cleaning this up with an observer but it would need access to the current user. Observers do not have access to the current user, neither should they (Law of Demeter).
Any suggestions how to DRY this up between controllers?
class ApplicationController < ActionController::Base
before_filter :init_request
def init_request
params[:editing_user] = current_user
end
end
I like using decent_exposure to dry up my controllers. It automatically finds or initializes a model instance, based on whether an :id was passed as a param, and it assigns the attributes from params[:model].
To finish drying up your code, you could use the new strategy support (see the end of the readme) to automatically set the editing_user attribute on your model.
You could try an after_filter for this. Perhaps something like so:
class ApplicationController < ActionController::Base
after_filter :set_editing_user
def set_editing_user
#object.update_attribute(:editing_user, current_user) if #object && current_user
end
The difficulty, of course, is that you'll be saving the object twice per call. Generally though creations and updates don't happen so frequently that two database commits is a serious problem, but if you expect to be the next Twitter -- with massive database insertion load -- it could be an issue.
You could also possibly set this in a before_filter, but then you'd have to find or set the object in a previous before_filter. Otherwise #object will always be nil and the before_filter will never fire. You can use the filter ordering methods prepend_before_filter and append_before_filter to ensure the correct sequencing of these filters.
starting from the rails blog tutorial, i want to have listing and create functionality on a single view. But i don't known how to design the controller to accomplish this.
The index view must show a simple list of posts and a form to create a new post.
Can i solve this with partials? How? I need a "new" and "create" methods? With only create is not enough?
class MyPostsController < ApplicationController
def index
#posts = Post.all
end
def new
end
def create
end
end
If you want to have the form in the index view, render the form. I'd recommend a partial, but it's not mandatory. Depending on the form implementation you may need a new Post model, that's as easy as putting a #post = Post.new in the index action.
The reason create may not be "enough" is because some forms are "for" an instance of the model. In those cases generally the new action makes a new Post and renders the form, whereas the create action actually saves (creates) it.
How can I get values from database in application.html.erb? I need to get those values for whole project. Those values will stay forever to all pages. How can I pass values to application.html.erb?
Is there anything like beforeRender?
Is there anything like appcontroller.rb to override actions?
You could use an application wide before_filter - like so
class ApplicationController < ActionController::Base
before_filter :load_application_wide_varibales
private
def load_application_wide_varibales
#var = Model.where :condition => "whatever"
end
end
#var would then be available in all your views
cheers
you can put method in the application controller
before_filter :load_data
def load_data
#data = Data.all
end
All controllers inherits ApplicationController, so data will be loaded at all actions. Now you can use #data at you application.html.erb file
The best way is probably to create a method in your application controller and declare it a helper method. Then you can call that method in application.html.erb. For example if you want to be able to use the current user throughout your application you'd do something like this:
class ApplicationController
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id])
end
end
Then in application.html.erb you can do the following:
Hello <%= current_user.name %>
It's also possible to use before_filter like to other answers suggest, but in this solution the database only gets hit when it's necessary. With before_filter it always gets hit.
In one of the controller, I need a specific layout. I added layout at the beginning. It works well.
But if I add an initialize function for some controller-based variable. Rails seems just ignore the layout command.
Is anyone have same problem? How can I fix it?
class AdminsController < ApplicationController
layout "layout_admins"
def initialize
#Title = "Admins"
end
def index
....... some code here
end
end
initialize is used internally to Rails to, well, initialize a new instance of your controller so it can then serve requests on it. By defining this method in this particular manner, you are breaking Rails.
There is a way through! A light at the end of the tunnel. A pot of gold at the end of the rainbow:
def initialize
#title = "Admins"
super
end
See that little super call there? That'll call the superclass's initialize method, doing exactly what Rails would do otherwise. Now that we've covered how to do it your way, let's cover how to do it the "officially sanctioned" Rails way:
class AdminsController < ApplicationController
before_filter :set_title
# your actions go here
private
def set_title
#title = "Title"
end
end
Yes, it's a little more code but it'll result in less frustration by others who gaze upon your code. This is the conventional way of doing it and I strongly encourage following conventions rather than doing "magic".
EDIT: If you're using Rails 5 then you'll need to use before_action instead of before_filter.
I'm not sure exactly how layout works its magic, but I'm willing to bet it's in a yield block in the ActionController#initialize method. So your overriding of initialize would explain the problem.
Looks like you have too options here:
Close out your new definition with super to call the ActionController initialize which should use the layout defined in the class.
eg:
def initialize
#Title = "Admins"
super
end
Use a before filter to initialize your variables. This is the Rails Way of initializing values in a controller
class AdminsController < ApplicationController
layout "layout_admins"
before_filter :set_title
def set_title
#Title = "Admins"
end
def index
....... some code here
end
end