Translate controller action_name in Rails 4 - ruby-on-rails

I want to translate my applications' views and as I'm using partial to render headers for each view like this:
<%=t "#{controller.controller_name.capitalize} #{controller.action_name}" %>
...I got stucked on translating them. How do I translate controller.action_name in custom translation file?
I've tried to access action names like this:
parkings:
index: "Parkings index"
new: "New %{model}"
And many different variations of it, but every one failed. Could you help me?
This is a fragment of my controller:
def new
#parking = Parking.new
end
def create
#parking = Parking.new(parking_params)
if #parking.save
redirect_to #parking, notice: t(:parking_created)
else
render action: 'new'
end
end
Thanks.

You should have the translations in your locale file. Add an underscore or hyphen to separate words in the key
eg:
# config/locales/en.yml
en:
parkings_index: Parkings index
parkings_new: Parkings new page
view file
<%=t "#{controller_name}_#{action_name}" %>

First of all, when you say #{controller.controller_name} it means that you have an object called controller accessible from your view, which is not true. Even if you manage to access the controller and the name of its action I don't think it's worth the effort and time.
Instead, you can structure your translation file somehow like this:
views:
model_name (parkings): "Parkings"
action_1_name (index): "Parkings Index"
action_2_name (new): "New Parking"
...
and in your view say (for example) <%= link_to (t "views.model_name.action_name"), :action %>

Related

Rails 7 help DRYing out image attachments?

Bear with me, I am new to posting and Rails so sorry if I mess up phrasing!!
I am working on a Rails app with many similar models. Each view has a _form.html.haml partial that differs in content but contains similar components, such as buttons to submit, delete, etc. Every model has_many_attached photos, and in the form you can add or delete photos. The haml for deleting photos looks like this, where variable is replaced with whatever view _form.html.haml is in:
.gallery#form
- #VARIABLE.photo.each_with_index do |image, index|
.overlay-container
.img-square{ :style => "background-image: url(#{rails_blob_url(photo(#VARIABLE, index))})", :alt => "Photo of #{image}" }
= link_to("Delete", delete_image_attachment_VARIABLE_url(image), method: :delete, class: 'button delete overlay')
To make the delete work on each photo, this code is in each controller:
def delete_image_attachment
#photo = ActiveStorage::Attachment.find(params[:id])
#photo.purge
redirect_back fallback_location: #VARIABLE
flash[:success] = 'Photo was successfully deleted.'
end
And routes.rb has this chunk of code for each model:
resources :VARIABLE do
member do
delete :delete_image_attachment
end
end
However, I have about a dozen models I need to do this on. My goal is to bring the gallery into a new partial, since it will be used in every _form regardless of the other content. However, the delete function (though the same for every controller) is tied to the controller/routes.rb of each model.
There must be some way of DRYing this functionality into a couple files instead of copy-pasting for each model, but my Google searches have not turned up anything. So, any guidance or better Rails convention is greatly appreciated!
If I'm understanding the structure properly, it sounds like you would want to do something like the following:
Create a top-level controller that handles deleting images
This could be used by any page.
This would require the following query parameters:
id the photo's ID to delete by.
redirect where to redirect the user after the action is completed.
Routes
Now there will only be 1 route to handle the controller above.
Create a reusable partial
For rendering a collection of images with a redirect url that allows you to set the following state for the partial:
photos a collection of images to render.
redirect_url this is passed as a query parameter to the centralized delete image controller.
Thoughts & Mocked Examples
This should be able to DRY up your implementation. Currently the only thing I see that couples the view with the deletion is the redirect URL. By abstracting that out and moving that essentially to a parameter for the partial will allow for re-use and flexibility.
You've already identified your coupling via #VARIABLE, here's a quick mock of how I would expect it to end up looking like:
Partial Template
.gallery#form
- #photos.each_with_index do |image, index|
.overlay-container
.img-square{ :style => "background-image: url(#{rails_blob_url(photo(#VARIABLE, index))})", :alt => "Photo of #{image}" }
= link_to("Delete", delete_image_attachment_url(image, redirect: #redirect_url), method: :delete, class: 'button delete overlay')
Ths would require: photos, and redirect_url
So make sure to set #photos and #redirect_url on the consuming controller.
Example with instance properties to access in the template
#photos = GET_PHOTOS_HERE
#redirect_url = 'some-redirect-path'
render partial: 'photos_partial'
Example with locals parameter for the template
photos = GET_PHOTOS_HERE
render partial: 'photos_partial', locals: { photos: photos, redirect: 'some-redirect-path' }`
Note: You may need to change how you access the local variables in the template.
https://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
Controller
def delete_image_attachment
#photo = ActiveStorage::Attachment.find(params[:id])
#photo.purge
redirect_back fallback_location: params[:redirect]
flash[:success] = 'Photo was successfully deleted.'
end
Routes
Here you would only have the single route for deleting any image attachment, and point at the single controller above.
delete 'resources/image_attachment/:id', to: 'resources#delete_image_attachment'
Note: Replace "resources" with whatever your controller name is, or the scoping/naming you would like.
PS: It's been a while since I've done Rails so I'm not completely certain on the accuracy or your environment.

How can I dynamically set a search form with a different route in Rails views?

I currently have a very simple form for search written in HAML:
%form.search{ method: 'get', action: '/users/search' }
...
What would be the correct rails conventions for rendering a different search route based on the model that the controller sets in an instance variable when rendering this view?
I found this blog post, but this code <%= form_tag(recipes_path, :method => "get" is not generic enough for me. I would like to set this value, recipes_path, based on the model that the controller is collaborating with when it renders this view. The search form could be used across multiple controllers with their own search action. My app can search on different pages for different models.
I can definitely come up with a way to do it, but I would like to know the 'right' way or I suppose the 'rails' way of dynamically setting the form action to a different controller action based on the data that the form will be searching against.
I don't know what the 'right' or 'rails' way of doing this is. (But, it sure isn't hand-crafting a form with %form.)
In my apps, I tend to only have one form partial that looks something like this:
app/views/widgets/form
- #presenter = local_assigns[:presenter] if local_assigns[:presenter]
= form_tag #presenter.form_path, remote: true, id: #presenter.form_id, class: #presenter.form_classes, data: #presenter.form_data, method: #presenter.form_method do
= #presenter.form_inner
In my presenter_base.rb file, I have something like this:
class PresenterBase
def render_partial
render(partial: "#{file_name}", locals: {presenter: self})
end
def render_form
render_partial 'widgets/form'
end
end
So, to render the form in a FooPresenter, I might do something like:
class FooPresenter < PresenterBase
def present
render_form
end
def form_path
some_form_path(and: :maybe, some: :query_params)
end
def form_id
'my-cool-form'
end
def form_classes
'some cool classes'
end
def form_data
{some: :form, data: :here}
end
def form_method
:post
end
def form_inner
...
end
end
Naturally, there's more to it than just that (like, how I get a plain old ruby object to render). But, that should give you a sense of one way of doing it.
A simple way if there are no complications and you follow the conventions, can be something like this
%form.search{ method: 'get', action: "/#{controller_name}/search" }
so if you are in users_controller, it will print "users", if you are in static_pages_controller, it will show "static_pages" and so on.

How to add views for custom member action in active admin?

I have to add view for custom action which is member action, and want to display association records on it. Is there way to add custom view instead of just adding html.erb in admin's view folder?
I dont want to add or create html files but by using the active admins helpers.
The member action in nothing else like a controller action, thats mean you can do the same things in it.
You can use thinks like:
render text: "Hello world!"
Or if you want a complex markup:
message1 = "Hello"
#message2 = "world!"
view = Arbre::Context.new(message: message, self) do
h1 do
span message
span #message
end
end
render body: view.to_html # or .to_s
You can use the following code for the render html for rails 4.1:
render html: '<html><body>Some body text</body></html>'.html_safe ## Add html_safe
But, if you use rails 4.2, so you can use the following:
render text: '<html><body>Some body text</body></html>'
I think the following answer is very useful for your question.
Ended up with adding the following in html.erb file in admin/user/messages.html.erb
<% view = Arbre::Context.new({messages: #messages, user: #user}, self) do
panel "Sent Messages" do
paginated_collection(messages, download_links: false) do
table_for collection do
column :id
column :content
end
end
end
end
%>
<%= view.to_s %>
Depending on your namespace (ActiveAdmin is on /admin in my case) you can create the folder app/views/admin in the same way you would in the rest of your application.
For example, if you have a resource User and an action apply_discount
ActiveAdmin.register User do
member_action :apply_discount, method: [:get, :put] do
if request.get?
render :apply_discount
else
# TODO ...
end
end
end
you could put your ARBRE view file into app/views/admin/users/apply_discount.html.arb -> notice the extension is ARB, not ERB - though ERB should work too according to the docs

Rails rendering a different view depending on the controller

I have a tab navigation page in my rails app which is shared across all of my views. Inside I have a small text area which should change depending on the page that the user is on.
Currently I am doing this by adding a variable to the controller and using it in the render partial path, like so:
class Myapp::WebsitesController < MyappController
def set_up
#page = 'websites/left_text_info'
end
and then in my partial:
<%= render :partial => #page %>
This works but it doesn't feel like the best 'ruby' way of doing things. Can anyone advise on a better way of doing this?
Thanks
You can use controller_name helper method directly in your view and skip the controller part:
<%= render "#{controller_name}/left_text_info" %>
Or if the only thing that change is the content of the textarea, then perhaps the best way is to define a helper method that returns only the content for it, so you don't need multiple partial files that are very similar.
module ApplicationHelper
def text_area_content
case controller_name
when "users"
"content for users"
when "articles"
"content for articles"
else
"other content"
end
end
end

creating dynamic helper methods in rails

I am trying to create a bunch of dynamic helper methods like these:
show_admin_sidebar
show_posts_sidebar
show_users_sidebar
So far I have this in my helper.rb file:
#spits out a partial
def show_sidebar(name, show_sidebar = true)
#content_for_sidebar = render :partial => "partials/#{name}"
#show_sidebar = show_sidebar
end
def show_sidebar?
#show_sidebar
end
In my application layout file I have this: (NB - I'm using HAML):
- if show_sidebar?
= yield(:sidebar)
This allows me to say the following in my views:
- show_sidebar(:foo)
- show_sidebar(:bar)
And this renders the desired partial.
The problem with this is that I can only add one sidebar per page. So, I figure I need to have dynamic methods like: show_admin_sidebar, show_foo_sidebar.
So I have tried to do this:
def show_#{name}_sidebar(show_sidebar = true)
#name = name
#content_for_#{#name}_sidebar = render :partial => "partials/#{#name}"
#show_sidebar = show_sidebar
end
and then in my layout:
- if show_sidebar?
= yield("{#name}_sidebar")
But rails does not like this at all.
I have tried almost everything I can think of in my helper file and nothing works.
The reason I am using helper methods for this is because I want my content div to be 100% page width unless there is a sidebar present in which case the main content goes into a smaller div and the sidebar content goes into it's own..
If I can't get this working, then I can easily fix the problem by just adding the partials manually but I'd like to get my head round this....
Anyone got any experience with this kind of thing?
The entire approach to this was bizarrely overcomplicated, didn't follow Rails conventions at all, nor make the slightest bit of sense, and shame on prior respondents for enabling this approach instead of helping him to simplify. My apologies for being 13 months late with the answer.
Your controller should be deciding if a sidebar is to be shown or not, and setting an instance variable #side_bar_name to either nil or a sidebar name string. Then somewhere in shared view code, probably views/layouts/application.html.erb, you would have something as simple as this:
<% if #side_bar_name %>
<%= render :partial => "partials/#{#side_bar_name}" %>
<% end %>
Or better yet:
<%= render(:partial => "partials/#{#side_bar_name}") if #side_bar_name %>
If you want to use a helper (which is not a bad idea for keeping your code DRY and readable) it would basically be the same code, just moved into the helper.
<%= side_bar_helper %>
def side_bar_helper
render(:partial => "partials/#{#side_bar_name}") if #side_bar_name
end
What the controller does is up to you. It would probably do something like this:
if session[:show_side_bar]
# maybe use cookies instead of session, or store user preference in a database
#side_bar_name = session[:side_bar_name]
end
Here is a solution for you, however I wouldn't suggest too much metaprogramming:
#Add the following snippet to the proper helper module:
['admin','user','whatever'].each do |name|
class_eval{
"def show_#{name}_sidebar(show_sidebar = true)
#name = #{name}
#content_for_#{#name}_sidebar = render :partial => 'partials/#{#name}'
#show_sidebar = show_sidebar
end"
}
end
def show_#{name}_sidebar(show_sidebar = true)
That doesn't look like valid Ruby to me. Are you parsing and evaling this yourself or just throwing that right in the file and expecting it to work?

Resources