How to add views for custom member action in active admin? - ruby-on-rails

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

Related

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.

Translate controller action_name in Rails 4

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 %>

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

Rails: set a value using a link

I need help trying to create a link that submits an edit form.
Let's say I have a list of objects
Object - Color - Own?
Ball - Red - false - [button]
Hat - Blue - true - [button]
Shoe - Green - false - [button]
When I click on the [button] I want to set "Own?" to True.
Routes
resources :toys
Controller
def edit
#toy = Toy.find(params[:id])
end
def update
#toy = Toy.find(params[:id])
if #Toy.update_attributes(params[:toy])
flash[:notice] = "Toy Updated"
redirect_to #toy
else
render 'edit'
end
end
View
<h2>Toys</h2>
<% if #toys %>
<% #toys.each do |toy| %>
<%= toy.name %> - <%= link_to 'Set Own', edit_toy_path(:id=>toy.id, :owned=>'true')%>
<br/>
<% end %>
<% else %>
None
<% end %>
This is all about how you setup your controller actions. I'm not totally sure I understand how you want to use yours, but I have a similar case that I'll show you which I think you should be able to adapt to your situation.
In my case, I have a menu button that sets a value in the session to either keep a menu panel open or closed across any views a user looks at.
First, you need a controller action that is going to do the work you're interested in. I created a "SharedController" which handles application-wide things that don't belong to any particular view or other controller.
class SharedController < ApplicationController
# Used by AJAX links to set various settings in shared views
def edit
session[:admin_menu] = params[:admin_menu].to_sym if params[:admin_menu]
session[:advanced_search] = params[:advanced_search].to_sym if params[:advanced_search]
render :nothing => true
end
end
This controller action can set one of two values in the session, either: "admin_menu" (boolean) or "advanced_search" (boolean). Then certain views ask whether the session value for admin_menu or advanced_search is true, and if so they show the view.
You could use the same logic. Something like:
def edit
object= Object.find(params[:object_id])
object.own = params[:own]
object.save
end
To trigger this controller action with a link you need to have a route that accepts GET requests. edit is a logical choice.
resource :shared, :only => [:edit], :controller => 'shared'
Note: I think SharedController makes more sense than SharedsController, and edit_shared_path makes more sense than edit_shareds_path, so I had to specify :controller => 'shared' in my routes.rb.
Then you just need a link to a url with params. To add params onto a path you just add them to the path helper, like so:
edit_shared_path(:key => 'value')
You can retrieve these params in your controller via:
params[:key]
Make this a link like so:
link_to 'Set Own to True for This Object', edit_shared_path(:object_id=>object.id, :own=>'true')
NOTE: It's best to do this via AJAX, so be sure to set :remote=>true. If you don't use AJAX then you need to specify a redirect in your controller for what page should be loaded after this link is triggered.
In the case of my admin menu preference link, I need a link with two possible states. I generate these using a helper:
# Shows Admin Menu Button
def admin_toggle_button
if session[:admin_menu] == :on
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :off), :remote=>true, :class => 'selected', :id => 'admin_toggle_button', :title => 'Hide Admin Menu' )
else
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :on), :remote=>true, :id => 'admin_toggle_button', :title => 'Show Admin Menu' )
end
end
In a view I just call this using admin_toggle_button. You can do something similar if you like, but it's optional.
I hope that gets you on the right track, let me know if you have any questions.
EDIT: Based on your comment:
Links issue GET requests, which mean you're going to the EDIT action. See: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
A further issue, you have resources :toys instead of resource :shared (which I used for this purpose). This means your link helper is already expecting a specific toy to edit, rather than handling a singular resource. See: http://guides.rubyonrails.org/routing.html#singular-resources
Your link would work if you changed it to be:
link_to 'Set Own', edit_toy_path(#toy, :owned=>'true'), :remote => true
... and set your edit action in your controller to the following:
def edit
#toy = Toy.find(params[:id])
#toy.owned = params[:owned]
if #toy.save!
head :ok
else
head :internal_server_error
end
end
See: http://guides.rubyonrails.org/layouts_and_rendering.html#using-head-to-build-header-only-responses
Now, be aware, you really should only do this with AJAX links, and you should normally not do it with your "real" controller. The reason is, now this is the only action that can be processed by EDIT, so your normal toys#edit view would no longer work.
You can get around this by create a new action and a new route, for instance:
resources :toys do
member do
get 'set_ownership'
end
end
Then simply take the same method above and call it set_ownership instead of edit. IE:
class ToysController < ApplicationController
...
def set_ownership
...
end
end
Hope that all makes sense.
The edit_toy_path method that your link_to method is calling is going to the edit action inside your controller. It's not going to the update method that I'm guessing you want.
Your link_to will need to change to something like:
<%= link_to 'Set Own', toy_path(:id=>toy.id, :owned=>'true'), :method => :put %>
But I question this particular approach. I don't think the variable will update correctly in the update action because it is not namespaced to the proper params[:toy] object that update_attributes is expecting. And in my quick and dirty tests I couldn't get it to namespace properly.
When I have a situation like the one that you are describing I usually setup another action, like toggle_ownership and I call that from my link_to with a :remote => true option. Then the controller toggles the attributes as desired.
Thus, my routes looks something like:
resources :toys do
member do
put :toggle_ownership
end
end
And my view looks like
<%= link_to 'Set Own', toggle_ownership_toy_path(toy.id), :method => :put %>
The controller sets the variable and renders back a toggle_ownership.js.erb file that updates the appropriate section of the page.
Hope that helps!

How to access validation messages in partials?

So, each rails project i seem to run into this problem and would be really grateful if someone could enlighten me:
With a "normal" setup when the form sits on the view immediately associated with the url/controller it is pretty straightforward, a render => :action on fail will display the validation message.
Now what i have is a form in a partial sitting on a page whose url/controller is a show/:id and not the create action of the form, the validation kicks in but i cannot get the validation message to display because i can't trigger the correct render action...
CLosest i got is a render => #object but there is no css/layout, i can pass a message through a redirect with flash[] but it feels wrong, same with jquery/client error messages...
So how can i "cleanly" display validation messages of a form in a partial (under another controller/action than the parent page)?
(thanks in advance for your help)
edit: can't paste the actual thing now but i'll do my best to explain
i have a main page e.g. article/show/01, on this page is the content of the article (#article) and then at the bottom of the page is a partial _commentform with a form to post a comment. This form is bound to a Create action of a different controller (comments controller).
Now if the form were on its own "page"/url instead of a partial, say /comment/create, i would jus do:
if #comment.save
redirect_to #comment
else
render => :create
end
and the validation would display normally.
In my case the form is in a a partial on the article/show/01 url, what should be the equivalent to the code above so that on validation fail error messages are displayed on the parent url, like "render article/show/01" ?
I am sure it is easy but i cannot get it to work (i just can redirect on success but cannot display the errors with a render)
I don't think the best way to display validations errors is to render a partial.
IMHO, the best and clean way to display errors messages using the styles/css you or your webdesigner wants is by implementing your own error_messages method in a FormBuilder.
For example, here is the error_messages method I've implemented for my latest project.
Here is an example that will output the errors list in ul/li's with some custom styles...
Just customize this and put your form builder in app/helpers...
class StandardBuilder < ActionView::Helpers::FormBuilder
def error_messages
return unless object.respond_to?(:errors) && object.errors.any?
errors_list = ""
errors_list << #template.content_tag(:span, "There are errors!", :class => "title-error")
errors_list << object.errors.full_messages.map { |message| #template.content_tag(:li, message) }.join("\n")
#template.content_tag(:ul, errors_list.html_safe, :class => "error-recap round-border")
end
end
Then in my forms :
= form_for #post, :builder => StandardBuilder do |f|
= f.error_messages
...
No need to display/render another partial. And that's all :).
If you want to display anything (including error messages) in a partial you have two ways
1 - Define it in the controller action where the partial is called
2 - pass the message as a parameter to the partial
1 - Example
in your controller/action
if #comment.save
redirect_to #comment
else
#messages = "This is a message"
render => :create
end
in your partial
you can access the #message variable
2 - passing the variable to the partial
render :partial => “<partial name>”, :locals => { :param1 => “value”}
<partial name> – name of your partial (Ex /partials/footer)
:params1 – parameter name
“value” – value
hope this helps
thanks
sameera

Resources