I know there are some preset structures in i18n locale file so that Rails pulls values automatically. For example, if you want to set the default submit button text for new records:
# /config/locales/en.yml
en:
helpers:
submit:
create: "Create %{model}"
user:
create: "Sign Up"
With this set, in views the following will result:
# /app/views/things/new.html.erb
<%= f.submit %> #=> Renders a submit button reading "Create Thing"
# /app/views/users/new.html.erb
<%= f.submit %> #=> Renders a submit button reading "Sign Up"
So Rails uses a preset hierarchy for getting the submit button text for different models. (i.e., you don't have to tell it which i18n text to get when using f.submit.) I've been trying to find a way to do this with flash notices and alerts. Is there a similar preset structure for specifying default flash messages?
I know you can specify your own arbitrary structures like the following:
# /config/locales/en.yml
en:
controllers:
user_accounts:
create:
flash:
notice: "User account was successfully created."
# /app/controllers/users_controller.rb
def create
...
redirect_to root_url, notice: t('controllers.user_accounts.create.flash.notice')
...
end
But it's tedious to specify the notice: t('controllers.user_accounts.create.flash.notice') every time. Is there a way to do this so that the controller "just knows" when to grab and display the appropriate flash messages specified in the locale file? If so, what's the default YAML structure for these?
The Rails i18n guide section 4.1.4 on "lazy" lookups says:
Rails implements a convenient way to look up the locale inside views
(Emphasis theirs, and implying to me, at least, that it is restricted only to views...) However, it seems that this commit to Rails brought "lazy" lookups into controllers as well, with the key being in the form of:
"#{ controller_path.gsub('/', '.') }.#{ action_name }#{ key }"
which in your case should get you users.create.notice.
So, if you're happy with something like:
# /app/controllers/users_controller.rb
def create
...
redirect_to root_url, notice: t('.notice')
...
end
You should be able to just declare that value in:
# /config/locales/en.yml
en:
users:
create:
notice: "User account was successfully created."
I know this doesn't take you quite all the way of having a default spot where Rails would automatically go and fetch a flash notice on failure to create a user, but it's a bit better than typing out a full i18n key every time.
I think that currenly (Fall 2015) the most graceful and somewhat conventional way to implement lazy flash messages for you controllers is to use responders gem:
gem 'responders', '~> 2.1'
FlashResponder sets the flash based on the controller action and
resource status. For instance, if you do: respond_with(#post) on a
POST request and the resource #post does not contain errors, it will
automatically set the flash message to "Post was successfully
created" as long as you configure your I18n file:
flash:
actions:
create:
notice: "%{resource_name} was successfully created."
update:
notice: "%{resource_name} was successfully updated."
destroy:
notice: "%{resource_name} was successfully destroyed."
alert: "%{resource_name} could not be destroyed."
This allows to completely remove flash-related code from the controllers.
However, as you have already understood, you'll need to rewrite your controllers with their respond_with method for that:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
respond_to :html, :json
def show
#user = User.find params[:id]
respond_with #user
end
end
Follow-up for #robertwbradford's comment on testing, in a Rails 4 / MiniTest functional (controller) test, you can call the translate method on the #controller instance variable:
assert_equal #controller.t('.notice'), flash[:notice]
Related
New web developer here, and I think I may be missing some very fundamental knowledge. Given the code
> def create
> #post = Post.new(post_params)
> if #post.save
> redirect_to #post
> else
> render "new"
> end
end
after saving the post, it redirects to show page, due to this "redirect_to #post", how can I do the same thing with "redirect_to: action => "show", :id => 5" I have to pass the ID now, how to retrieve the ID from #post object?
so only I can pass the Id to redirect page.
can I stop the compiler here, like debugger in js?
To answer your question of "I may be missing some very fundamental knowledge" yes, you might be. An object in Rails like #post is usually a database record. You can access any of it's columns in the DB by using the column name as a method:
#post.id
returns:
5 #or whatever the post id is.
If your post table has a column of "title" you can access it with
#post.title
returns:
"This is an awesome post"
I would highly recommend you view some Ruby and some Rails tutorials. Everything in Ruby is an object. Rails uses a lot of conventions so you can do things without having to write code for it, it's already there for you. When you get into Rails ActiveRecord Relations you'll see that relations expand this to give you related table information as methods. For Example:
Post.rb
...
belongs_to :user
User.rb
...
has_many :posts
Gives you methods like:
#post.user #returns the user object with all of its info
#post.user.username #returns the value of that column for that user
#post.user.posts #returns an array of Post objects that belong to the owner of that post.
Ruby has a pry-byebug gem for debugging. It's a combination REPL (Pry) and core debugger (byebug) that work very powerfully together.
Getting the id of a successfully saved ActiveRecord model is just #post.id, however the rails methods like redirect_to will take the object itself just fine, as #Beartech has mentioned, above. The documentation shows a variety of ways to use it, for convenience:
redirect_to action: "show", id: 5
redirect_to #post
redirect_to "http://www.rubyonrails.org"
redirect_to "/images/screenshot.jpg"
redirect_to posts_url
redirect_to proc { edit_post_url(#post) }
In my current app, i use Geocoder gem to get the city and the country of the visitor. I use hidden fields in my view to get these details. When the login form is submitted, these details will be sent to the controller and the controller will save them to the database. When I try to get these details directly from the controller by using
request.location.city
It will assigning a blank value to the database. If I use hidden fields in the view, some one can temper with them right? So, how can I fix this?
You should store visitor information before you render any content:
class UsersController
def new
# I suspect that, for fast insert, you should probably use a NoSQL database
# to perform `store!` or even just write it to a log file
Visitor.store!(:city => request.location.city, :ip => request.ip)
end
def create
#user = User.build(params[:user].merge(:city => request.location.city))
if #user.valid?
#user.save
flash[:notice] = "You've been registered!"
redirect_to user_dashboard_path
else
flash[:notice] = "Couldn't register your account"
render action: "new"
end
end
end
I am a beginner of RAILS.
I wrote some code , which validate if the cvs I load is correct
I have also a controller Employee (in this controller I will put validation) :
def import
if params[:csv_file]
Employee.import_from_csv(params[:csv_file], #organization, current_user)
redirect_to admin_organization_employees_path(#organization), :notice => "Your request has been accepted! We will inform you via email about the results!"
else
redirect_to :back, :notice => "Missing file"
end
end
In which place should I put Class CSV_Validator which has lots of code?? In Lib how to use it?
In your model.
Just as rule of thumb, place the bulk of your code in models.
Rails doc
I have a form where I have an administrator creating new users. The form uses the User model I created (login, password, first_name, etc...). For the last field on the form, I want to have a checkbox that doesn't need to be stored as part of the User record, but it is needed for the controller. This will control if the newly created user will receive a welcome email or not. This is in Rails 3.0.3.
def create
#user = User.new(params[:user])
if #user.save
if #user.send_welcome_email
UserMailer.welcome_email(#user).deliver
end
redirect_to(admin_users_url, :notice => "User #{#user.name} was successfully created.")
else
render :action => "new"
end
end
In my view (haml) I am trying to access it like this:
%p
Send Welcome Email?
= f.check_box :send_welcome_email
I tried to make this an attr_accessible: :send_welcome_email but the controller does not recognize it. I get an
undefined method 'send_welcome_email' for #<User:0x00000100d080a8>;
I would like it to look like this:
What is the best way to get this working?
What you want is not attr_accessible, but attr_accessor. That's it.
However, your code will look nicer if you move the email sending code to an observer.
Since you're not saving it on the user, you can use check_box_tag instead of f.check_box and access it with params[:send_welcome_email]. Although even the way you have it, I think you could access it as params[:user][:send_welcome_email].
As an alternative to attr_accessor, you can always remove it from the parameters first:
def create
send_welcome_email = params[:user].delete(:send_welcome_email)
#user = User.new(params[:user])
if #user.save
UserMailer.welcome_email(#user).deliver if send_welcome_email
redirect_to(admin_users_url, :notice => "User #{#user.name} was successfully created.")
else
render :action => "new"
end
end
You may have to make sure that the parameter is successfully transformed into a boolean; otherwise the condition will always be true (0 is true in Ruby).
I have the following two action methods:
def index
puts "==index== flash: #{flash.inspect}"
end
def create
flash[:notice] = "Blah"
puts "==create== flash: #{flash.inspect}"
redirect_to(:action => :index)
end
index.fbml.erb contains this:
<%= button_to_with_facebooker "Blah!", :action => :create %>
The application is used through Facebook. I click the button and the flash contains the notice while create is being executed, but after that it's empty again. It doesn't survive a redirect. Any ideas what's going on here?
I've found one workaround. While using ActiveRecord to store the session, add
ActionController::Dispatcher.middleware.delete Rack::FacebookSession
ActionController::Dispatcher.middleware.insert_before(
ActionController::Base.session_store,
Rack::FacebookSession,
ActionController::Base.session_options[:key])
in an initialization file, like config/initializers/session_store_fix_facebooker_session_key.rb
This has been done on by someone else before and he explained it on a message on the Facebooker group on but it doesn't work with the cookie session storage, Rail's default.