ActiveAdmin - how to delete ALL objects (not only those on current list page) (Rails ') - ruby-on-rails

On my ruby on Rails app using ActiveAdmin, I wish to delete not only the 30 Users displayed but all the 456 users (that's an example of course).
When I select "select all' and then confirm deletion, it only deletes the 30 users visible on the current screen page.
I want to select ALL users (across all view pages, not only the one I currently see), and then manually deselect the first 4 users (or any I would manually pick on the current view page). So not really deleting ALL users. that's my problem.
How to customize ActiveAdmin to be able to do this ?

Maybe something like this would work:
https://github.com/activeadmin-plugins/active_admin_scoped_collection_actions
Plugin for ActiveAdmin. Provides batch Update and Delete for scoped_collection (Filters + Scope) across all pages.

If you want to delete some users from a list of all of them, I suggest you to write a custom active admin action. Minimize your markup, make it easy to render for browser and prepare for the worst. If you have 1 million records, there is no way it will work properly, there is no solution for that.
I suggest you to accept the fact that user will delete records by using search, probably and if you literally want to be able to delete all you can provide a custom button delete all that will do that for you.
The alternative is write a custom active admin action with a lot of javascript to provide pagination. It's still a lot of custom code, no generic solution provided.
Last alternative, you can disable pagination for that active admin page, but you may have a lot of problems loading the entire table every time

You can override the default batch action to destroy/delete all the users like this:
ActiveAdmin.register User do
batch_action :destroy do |ids|
User.delete_all
redirect_to collection_path, alert: "Deleted all the Users!"
end
end
See this for more information.

Related

Rails adding row to DB through admin approval

I am making an application in Rails and I have Devise about to be included for users management. I have an index page where all the database rows are in with CRUD ability which is all good.
The functionality I'm after is that if a user wants to add a new row, they can go through and 'add' it but before it gets actually added, the request goes through to an admin, then the admin can hit 'approve' and then the row gets added.
The issue is me trying to get around the fact that the program would 'hold' an action of adding a row and the admin would approve it, then the program would let that action apply.
Thanks.
Instead of going through the hassle of preventing saving the row to the DB (you'd have to cancel the saving in a before_create callback but keep the data somewhere anyway and pass them to admin for approval somehow), I'd do a much simpler approach.
Add another column to the table, boolean column named e.g. approved and by default show only all approved rows in the listing. When a user creates a row, save it with approved = false and let admins access these unapproved rows and approve them simply by setting approved = true or delete them if approval is denied.
Also consider creating a DB index for this column for performance reasons.

Copy a dynamic page in a view

My knowledge of Rails is pretty basic, but I have to fix a problem in a Rails project and the programmer can not be reached. So I'm trying to fix it myself, but I'm stuck.
The project revolves around user being able to add pictures to competitions, and to be able to vote on those pictures. The plan was to have to voting on the same page as the images, but this gives a few bugs in the JS and slow performance. So I want to have the voting and the overview on two different pages.
The problem is that I can't figure out how to create another page inside the views > competitions folder and link it up with the rest of the project. The easiest solution for me would be to copy the show.html.haml and paste it like votepage.html.haml but obviously that isn't so easy.
in the view > competitions folder there's an index.html.haml file, this displays a list of current competitions and gives a admin the ability to remove, add or edit certain competitions. When a user clicks on a link to a competition this gets rendered in the show.html.haml. On this page all the images that have been uploaded in that competition are shown. On that page I want a link that refers to the voting section. When a user clicks that link it should go to the votepage.html.haml (which is 100% the same as the show.html.haml but with different styling and added javascript). For now there's no need to actually make the voting work, "faking" it through front-end is good enough.
TLDR: I want to copy/paste a page in a view, but I don't know how to hook it up to the project.
Update1. I've used the console command rails generate controller competitions votepage which created a votepage for me. I could visit this one as well on http://localhost:3000/competitions/votepage
With the following code
- #competitions.each do |competition|
#container.js-masonry
.painting.item
= link_to competition do
- competition.pictures.shuffle.each do |picture|
= image_tag(picture.image_url)
I can insert images from the competitions in the page. But the problem is that I gets images from all competitions. And not so much competitions/1 , competitions/2 etc.
What you're missing is updating the routes file so that Rails knows what you want
Views:
competitions/
show.html.haml
vote.html.haml
...
Routes:
resources :competitions do
get :vote, on: :member
end
Member makes it behave like the show action, requiring a format like competitions/:id/vote
Edit:
You want to do the routes like above, but in the controller, make sure you get the competition from the id that will get passed
Controller:
def vote
#competition = Competition.find(params[:id])
end
And then instead of looping through all the competitions, you can just take the loop out and reference #competition
The basic answer is that you also need to copy the show method from app/controllers/competitions and make a votepage method with the contents in the same file.
This guide will help explain how views get wired (by the controller) to models: http://guides.rubyonrails.org/action_controller_overview.html

Rails + Devise: How to restrict a user from editing records that do not belong to him

I'm using Rails, Devise and Mongoid.
A user can only have one project (has_one :profile) but all users (and non authenticated users) can see a list of projects (I have this working). When a user is logged in they see "edit and delete" buttons next to the projects (via wrapping those buttons in <% if user_signed_in? %>). However, a signed in user sees these buttons next to all project and can edit or delete them all.
How do I restrict a logged on user to only be able to edit only his project?
As a bonus, is it possible to show specific content or html around the project that belongs to the signed in user (such as text that says "this is your project" or an additional class around the project's html)?
CanCan is great when you have multiple users being able to modify the same resource, and you need to keep track of who has which permissions. But if it's strictly the case that only the user who owns the project can modify it, CanCan is probably overkill.
Hide the links in the view as suggested by iouri, and then in your controller do something like:
def edit
if current_user != #project.user
# Redirect them to an error page
else
# Render the view
end
end
Better yet, create a method like:
def user_owns_project?
#project.user == current_user
end
Then set up a before filter for edit, update and destroy to redirect to the error page if the user doesn't own the project.
EDIT: Your before filter will also ned to find the project and set #project. CanCan takes care of this for you too with load_and_authorize_resource, but I'd still avoid using it unless you need, or expect to need, fine-grained permissions control.
Devise is to control "authentication", this should not to be your responsibility.
You want to control "authorizations", for that CanCan is better.

How to disallow select from a nested resource in rails?

I have a rails app that is multi tenant. It has resources for Account, Client, and Transactions. An Account has many Clients has many Transactions. I want to make sure I can never accidentally do Client.find, Transaction.find, etc (everything must go through the_account.clients.find, or client.transactions.find, etc). I want to do this so I don't accidentally show the wrong users things from the wrong account by forgetting to first select on the Account.
Is there a way to disable the Client.find (Client.find_by_name, Client.find_by_etc) but still allow the_account.clients.find?
I don't know about completely disabling Client.find, but I'd probably put a method into the bottom of each of my Client and Transaction controllers to handle lookups. Here's what the Client code would look like:
def collection
if current_user.admin?
Client.all
else
current_user.account.clients
end
end
Then, everywhere in my controller I'd ordinarily use Client.find, I'd substitute collection instead. Gets you all the right records without risk of over-exposure.

Ruby on Rails (3) hiding parts of the view

I am working on a Ruby on Rails 3 web application.
I have a table named User with a coulmn named role. I am looking for the best way to hide parts of the view from users that have the "wrong" role for those parts of the view.
For example I want all users to be able to see the users index page, but i want only users with a role - admin to be able to edit other users.
So first I block the edit action using filter_by, but what I also want is make the edit button not to appear.
The current user is saved in the session, so checking the user role is very simple.
What I am asking, is there an easy way to do so besides the obvious if statement before each button I want to hide. I would think that rails would have an easy way to do this type of thing, I couldn't find one.
You may want to use Devise and CanCan.
https://github.com/plataformatec/devise
https://github.com/ryanb/cancan
Here is a RailCast tutorial
http://railscasts.com/episodes/192-authorization-with-cancan
if you wanted to clean it up a tiny bit you could write yourself an application helper:
def if_admin(user)
if(user.is_admin? && block_given?)
yield
return
end
end
then in your view you could write:
<% if_admin(#user) do %>
<some admin only html />
<% end %>

Resources