ActiveAdmin batch_action template error and no update - ruby-on-rails

My ActiveAdmin registered model has an "active" boolean field. I want to include a batch action to "activate" multiple records at once.
I am trying to follow the instructions at:
http://activeadmin.info/docs/9-batch-actions.html
for doing a custom batch action and I am having two problems.
I have this:
ActiveAdmin.register Venue do
batch_action :deactivate do |selection|
Venue.find(selection).each do |v|
v.active = false
end
end
end
When I try to activate something I get a template not found error. It is looking for a "batch_action" template. I didn't see anything in that doc about needing to also add a template. If I add a template with that name the error goes away and it displays the template...this is of course not what I want. I want it to just redisplay the index.
In either case (with or without a template in place), the model is not being updated. I can see in the log where it just does a select for the selected records and does nothing else.

I got rid of the issues by doing the following:
batch_action :activate do |selection|
Venue.find(selection).each do |v|
v.active = true
v.save
end
redirect_to :back #this ensures any current filter stays active
end
The 'save' part seems obvious but the example in the docs threw me off on my first attempt. It seems like this would be a more relevant example for the docs.

Related

How to compare two items within Ruby on Rails?

So I'm trying to re-create GitHub version control for let's say posts. I've found a way to re-create an original post using duplicate AND another method to create a new post based on the original. Cool.
My issue is being able to display both the original and the new on the same page.
What I've attempted thus far is to just rely on the show method with having:
def show
#post = Post.find(params[:id])
end
Then in the view have in the form a checkbox to allow a user to select multiple posts, click a submit, and a new page renders displaying both side by side. Preferably showing the differences between the two but that's a wish list as I deal with this first.
Actually could I just simply do?:
def other_show
#post = Post.where(params[:id])
end
I also added in status as a boolean to help on the view for marking the checkbox. Would I then need to put something in the other_show method about the status?
If you want to "recreate" some sort of version control I suggest you use something like the audited. Instead of building your own. From your example and comments it seems you don't have a clear relation between all related (versions of) posts.
Using this gem, each change to the Post content (for example, if configured properly) would be stored as an audit.
Showing the differences is a different problem. That's usually called a diff and you can find gems that do it for you, for example: diffy
To show 2 different entities on one page you need to give posts_controller both ids.
Declare your show method like this:
def show
#original = Post.find(params[:id])
#compared = Post.find(params[:compared_id])
end
Correct route to this method will look like this:
/posts/:id?compared_id=:another_id
# Example: /posts/1?compared_id=2
To construct such a link in your view, you need to declare link_to method like this:
<%= link_to '1 <> 2', post_path(#post, compared_id: '2') %>
If you want to have a page where user can check 2 checkboxes for certain posts, you'll need to construct such href via Javascript.
But in fact I wouldn't suggest you to modify show method for such a task. It is better to use show method only for showing one entity from database. You can create another method, e.g. compare and pass both parameters there.
def compare
#original = Post.find(params[:original_id])
#compared = Post.find(params[:compared_id])
end
In routes.rb
resources :posts do
get 'compare', on: :collection
end
It will give you helper compare_posts_path, which will lead to /posts/compare and you'll need to pass original_id and compared_id to it, like this:
<%= link_to 'Compare', compare_posts_path(original_id: 'some_id', compared_id: 'some_another_id') %>
It will result to
/posts/compare?original_id=some_id&compared_id=some_another_id

ActiveAdmin and handling a subset of data

We use ActiveAdmin and have a notion of an event at like http://domain.com/admin/events/3/edit. I'd like to be able to edit the finance data aspect of this (something like http://domain.com/admin/events/3/finance/edit or http://domain.com/admin/events/3/edit/finance). How would you organize it? I was thinking of trying to do a custom controller like this:
ActiveAdmin.register Event, as: 'Finance' do
permit_params %i(venue_id name event_type_id)
before_create do |event|
event.created_by = current_user
end
show do |event|
panel 'Details' do
attributes_table_for event do
row :id
end
end
end
end
but this doesn't seem to work. What would be the most basic pattern to have a controller which has a portion of our data and can work well within ActiveAdmin?
You appear to be asking about nesting a resource inside another, see 'Belongs To' on this page

Why does validation error appear on the form after successful submit and going back?

I'm using Rails 4 and Chrome. The following results in the situation:
Post a form that causes a validation error (ie. "Name cannot be empty")
Post that same form successfully by correcting the input
Hit the browser back button and the validation error from step 1 is shown on the input field even though it has a value that is not empty
Why does the validation error from the step 1 pop back and how to fix this behaviour? Note: Turbolinks is in use, could that be the reason?
Here's the way to replicate:
rails g scaffold Page name:string
class Page < ActiveRecord::Base
validates :name, presence: true
end
Navigate to /pages/new
Submit (errors appear on the form)
Fillout the name
Submit again (redirected to successfully created model)
Hit the browser back button (the validation errors are there, and the field is filled with the last supplied value)
I guess you are using something like the following code to send back the errors related to the record being created/updated:
def update
#post = Post.find(params[:id])
if #post.update_attributes(post_params)
# your logic when successfull
else
render :edit, flash[:errors] = #post.errors
end
end
Or something similar. My point here is that you should use the following syntax for setting the errors in the flash :
flash.now[:errors] = #post.errors
(1) This should set the flash[:errors] available only for the current page and delete it right after you leave this page.
(2) You could also use flash.clear at the end of your view, but this is not how it is supposed to be done, and seems a little bit "hacky".
Resources:
(1) Rails' documentation about flash
(2) flash.clear method
(1) & (2) Why flash message won't disappear?

ActiveAdmin display default view content

I am working with ActiveAdmin and need to make customizations to some views and have come across a couple of scenarios I feel I am doing wrong.
I am adding an additional table to a show view (comments on Posts). This requires me to rewrite the whole attributes table and then add my panel. Is there a way to customize views without losing the default content?
I would also like to add a table of associated items on the show view which doesn't need to be customized is there any way to include the default tale that would normally be on the index view with default actions and paging?
After digging in the source code of Active Admin, I've found a way to patch this
show do
default_main_content
panel "Your Added Stuff" do
# Add stuff here
end
end
Of course this is undocumented and maybe considered a hack, but unless any other solution exists, it works.
Note: To do this in the form action (new and edit):
form do |f|
f.inputs
# Other inputs here
f.actions
end
Instead of using default_main_content, you could also just loop through the columns on the model like so:
ActiveAdmin.register Ad do
show do
attributes_table do
default_attribute_table_rows.each do |field|
row field
end
# Custom bits here
end
end
end
A couple areas of the documentation might help you:
See Customize the Show Page, Customizing the Index Page, Customizing the Form, and Custom Pages. An example of customizing a show screen:
ActiveAdmin.register Ad do
show do |ad|
default_main_content
h3 ad.title
end
end
See Custom Action Items in the Custom Controller Actions section of the documentation. An example:
action_item :only => :show, :if => proc{ current_admin_user.super_admin? } do
"Only display this to super admins on the show screen"
end
NB default_main_content does not exist in the documentation anymore, yet it works fine.
Just figured that out myself:
For the default table index page you can do something like this
index do
h1 "Hello World"
p "get more content"
instance_eval(&default_table)
end

How to require a value is entered in a search form

I built a basic search form that queries one column in one table of my app. I followed episode 37 Railscast: http://railscasts.com/episodes/37-simple-search-form. Note I just posted another search related question, but it's on a completely different issue.
In my app, the search queries the zip code column of my profile table, and returns a list of profiles that contain the right zip code.
Here's my problem. Currently, when a user leaves the input blank and hits the submit button, the search displays all profiles on the site. I don't want this to happen. If the field is blank, I don't want the search to go through. I'd like to either do a flash notice or throw an error, explaining that the user needs to enter a zip code to proceed.
Here's my setup:
PROFILES CONTROLLER
def index
#profiles = Profile.search(params[:search])
end
PROFILE MODEL
def self.search(search)
if search
find(:all, :conditions => ['zip LIKE ?', "%#{search}%"])
else
find(:all)
end
end
PROFILE/INDEX.HTML.ERB
<% form_tag ('/profiles', :method => :get) do %>
<%= text_field_tag :search, params[:search], :maxlength => 5 %>
<%= submit_tag "Go", :name => nil %>
<% end %>
Thanks!
def index
#profiles = Profile.search(params[:search]) unless params[:search].blank?
end
You probably don't want to throw an error if the search field is blank, because the user will see that error the first time he comes to the index page. To properly handle that type of error message, you'll need to do one of several things.
Split the form generation and the actual search into two separate actions. In a RESTful app, this would typically be a new and create action. (new for the form, create for the actual search).
Add a check for a post, as opposed to a get. Only attempt the search, or throw the error, if it's a post. Otherwise, just show the form. You'll typically see this in older Rails examples (like pre- 2.0 tutorials).
Add some hidden field that says "Hey, I'm submitting a search." This is the same idea as checking for a post, but would still work if you wanted all gets for some reason.
My choice would be the first one. It'd roughly look like this.
def new
end
def create
if params[:search].blank?
flash.now[:error] = "Please enter a zip code to search for."
render :new
else
#profiles = Profile.search(params[:search])
render :show
end
end
In your views, new.html.erb (or .haml or whatever) would contain your search form and show.html.erb would contain your search results. Usually there's a search form partial that both of them would share.
You just need to check if it's blank before you do your search.
def index
if params[:search].blank?
flash[:error] = "Doh! You forgot the zip code."
else
#profiles = Profile.search(params[:search])
end
end
If returning all results is never a use case then you might want to remove that code from your model as well. Also if you're checking for a blank search in more than this one controller action you should move the logic into the model.
I actually found an answer to this that doesn't require me to make any changes to my current setup.
If you look in the search model above, which I copied from the Railscast, you see that Ryan included wildcards on both sides of the search query:
find(:all, :conditions => ['zip LIKE ?', "%#{search}%"])
I'm not familiar with sql syntax at all, so I missed that. It was those wildcards that was letting through the blank search and returning all results in the database. When I removed the "%'s" from that sql statement, the blank search now returns the same result as a search where we don't have a record matching the zip queried, which is the result I wanted.
Just wanted to share so others might catch this in the future.

Resources