We have an CMS application which allows to create shops from a backend for multiple users.. now when we want to implement translations we face a problem. Translations are just stored with a locale but what we need would be a user.id and a locale. Because each user can have his own translations per language.
I tried to implement a i18n Backend as described in this railscast but am now stucking with
http://railscasts.com/episodes/256-i18n-backends?view=asciicast
the customization per user.
is there a way to add an additional column into the translations and ask for local and user_id?
many thanks
There is not a single best solution for your given problem. It depends on your application. Given the information I have I'd suggest something like:
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_filter :set_locale
private
def set_locale
I18n.locale = current_user.language || I18n.default_locale
end
end
This would set the 18n.locale to the language settings of your current_user. Obviously you need a language attribute in your users model for this to work.
Please have a look at http://xyzpub.com/en/ruby-on-rails/4.0/i18n.html for more examples.
Related
I have a website with 2 languages. I want to create a subdomain for each locale. For example:
en.site.com and fr.site.com.
I've googled, but no luck. I've only found solutions that extract locale name from query, for example: site.com/en/post/1
How can I implement such thing?
you can find an example in the rails guides: http://guides.rubyonrails.org/i18n.html#setting-the-locale-from-the-domain-name
its about domain names, but you can adapt it to your needs pretty easily.
keep in mind that subdomains introduce a lot of complexity into your app. cookies, javascript and ssl are sensitive to domains. make sure, that it's worth using subdomains vs. paths.
i find a simple example you can follow pretty easy in medium:
https://medium.com/unexpected-token/making-your-website-multi-regional-using-top-level-domains-cdbbdb951b65
the idea is to define a clear one-to-one mapping between the locale and the host
HOSTS_MAPPING = {
'en' => 'en.example.com',
'fr' => 'fr.example.com'
}
then use new mapping in ApplicationController
class ApplicationController < ActionController::Base
before_action :set_locale
def set_locale
I18n.locale = HOSTS_MAPPING.invert[request.host] || I18n.default_locale
end
end
it's say that your host en.example.com will use locale en
I've installed rails_admin gem on my localized site (2 languages) and i need administration (/admin) to be always in English. According to documentation I should add following 2 lines to beginning of rails_admin.rb file.
require 'i18n'
I18n.default_locale = :de
But it's not working. Any idea how to do that?
Stumbled over the same Issue. Here is how I solved it:
class ApplicationController < ActionController::Base
include Clearance::Controller
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :set_locale
def set_locale
if [Clearance, RailsAdmin].include?(self.class.parent)
I18n.locale = :en
else
I18n.locale = params[:locale] || I18n.default_locale
end
end
end
RailsAdmin controllers are inheriting form your ApplicationController so you need to tell them explicitly to use the locale :en there or you can open the classes and overwrite set_locale.
It does state on the documentation that you only need to do this if your local is set to something other then English so you may find that you do not need to set this. If you do need to set this then make sure it is below the RailsAdmin.config do |config| line in rails_admin.rb
Update -
As you are still running into problems could you please let me know what version of ruby you are using? Have you run a bundle install? Could you try sudo gem install i18n. Also if it cannot find your locales you may need to point it at them i.e I18n.load_translations "#{RAILS_ROOT}/locales/#{locale}.rb"
I am working with rails and am trying to implement a feature into my blogging application. I would like to have the option to choose a design for my blog. I would of course make the design and code them but after they are coded I would like to have the choice of using one of my designs.
How would/should I approach this?
Make controller for choosing design form list (of course check vaild of choise). Save choose in session and try this:
In layout:
= stylesheet_link_tag #custom_css
In application.rb
class ApplicationController < ActionController::Base
before_filter :check_css
def check_css
#custom_css = session[:css]
#custom_css ||= 'default'
end
end
I think that should work.
Other idea is change to different layout.
class ApplicationController < ActionController::Base
layout :custom_layout
def custom_layout
session[:css].nil? ? session[:css] : 'default'
end
end
My project name is clog, so I named my models and controllers like this: Clog::User Clog::Userscontroller.
Is this naming convention mandatory?
No, in a conventional Rails project, that's not necessary. Just name your models and controllers the usual way, like eg User or UsersController.
The other thing is that, when your project grows in size, you may need to organize your models into submodules. One approach to do so is extending your models with app concerns, as show eg here or here.
As for organizing controllers, one approach is to create a module in the lib directory, which you then include in your ApplicationController, like so:
In lib/authentication.rb:
module Authentication
def self.included(base)
base.send :before_filter, :login_required
base.send :helper_method, :current_user, :logged_in?
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token]) if cookies[:remember_token].present?
end
#...
end
In app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include Authentication
#...
end
For this to work, you need to add
config.autoload_paths << "#{config.root}/lib"
to your config/application.rb file
However, if you plan to build your Rails project as a Rails Engine, you may want to follow some naming convention. A good example of a Rails Engine is forem.
Yes, following the naming convention helps a great deal because not only does rails use it to generate other names, but other gems as well.
Specific to your question, you may be asking if you need to name the controller as UserController given that your model is called User. That is not necessary at all, and you may call it anything else if it better fits your purpose.
In this case, you will probably want to create a few controllers like so:
My::AccountController # for e.g.. /my/account
Admin::UsersController # for e.g. /admin/users/1
For a user, you refer to your own user record, as 'your account' so this makes more sense. However, the administrator's perspective would be to manage user records. You may also name a controller one thing and serve it under a different route. In your routes file, you may do this:
namespace :admin do
resources :users, :path => "user-accounts"
end
To reiterate, your model name need not match up to the controller name. They are only named similarly by association: UserController is understood to handle User records.
railstutorial.org has a suggestion which strikes me as a little odd.
It suggests this code:
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
end
The include SessionsHelper makes the methods available from ApplicationController, yes, but it makes them available in any view, as well. I understand that authentication/authorization is cross-cutting, but is this really the best place?
That seems to me to be potentially too broad of a scope. Putting code which implements, say, a before_filter which conditionally redirects (as the railstutorial.org example does) in a module which more commonly contains view helpers seems surprising.
Would functionality not strictly needed in views be better placed in ApplicationController or elsewhere?
Or am I just thinking too much about this?
Indeed, your feeling is correct.
I would implement this the other way around: add the functions sign_in and current_user to ApplicationController (or if you really want to: in a separate module defined in lib and include it), and then make sure that the current_user method is available in the view.
In short:
class ApplicationController
helper_method :current_user
def sign_in
end
def current_user
#current_user ||= user_from_remember_token
end
end
Of course, if you have a lot of code to place into your ApplicationController it can get messy. In that case I would create a file lib\session_management.rb:
module SessionManagement
def self.included(base)
base.helper_method :current_user
end
def sign_in
..
end
def current_user
..
end
end
and inside your controller you can then just write:
class ApplicationController
include SessionManagement
end
They seem to be taking (sneaky) advantage of the fact that, in Rails, Helpers are just ruby Modules.
Placing behavior that is shared across Controllers in a Module is, in my opinion, good practice. Putting it in a Helper, on the other hand, is potentially misleading and I would avoid it. Place it in a “standard” Module.
This is a philosophical question on the same level as the argument that questions the REST method provided in scaffolding and if A scaffold is worth having at all. You have to consider the fact that the tutorial book in RailsTutorial.org is a get-up-and-go Rails instructive guide. So for the purpose which it serves, I think it does the job.
However, is there a better place to put code needed across controllers and views? Yes, there is.
Some may follow Michael Hartl form Railstutorial and include the entire SessionHelper into the ApplicationController
Others may decide to expose only the essential helpers needed for the view i.e. sign_in, sign_out, current_user and the like.
I see a suggestion to put such code in the /lib directory and include it where needed.
All are viable options. Whichever you take may not matter that much in performance because Ruby would have to parse the file which you want to call (or include) a class, module or method from. What happens is, before any code is executed in a class, Ruby goes through the whole class once to know what's in it. It all depends on what one needs and the design of their app
FWIW, I store the current user in the User class:
class User < ActiveRecord::Base
cattr_accessor :current
...
end
This can be referenced in all 3 MVC tiers; it is set in the controller like so (and likewise on login, of course):
def set_current_user
User.current = (session[:user_id]) ? User.find_by_id(session[:user_id]) : nil
end
Among other things, this allows me to have audit logs at the ActiveRecord level that capture the current user (when applicable).