Seems like the tutorial located here has a couple omissions:
When creating the admin accessible controller method, they don't specify which custom devise controller to use, or which base controller to inherit from. So I've placed my code in a PagesController:
class PagesController < ApplicationController
def approve_users
if current_user.admin?
if params[:approved] == "false"
#users = User.find_by_approved(false)
else
#users = User.all
end
end
end
end
The view code that allows you to switch between all users and all unapproved users results in a NoMethodError in Pages#approve_users: undefined method 'each' for User whenever you select to show the users for whom :approved => false. I know why noMethodErrors spring up in app development, and would normally be able to wrap my head around why I'm getting this error. It works when #users = User.all, but not when #users = User.find_by_approved(false)
<% if current_user.admin? %>
<h2>Users</h2>
<%= link_to "All Users", :action => "approve_users" %> | <%= link_to "Users awaiting approval", :action => "approve_users", :approved => "false" %>
<div class="ui form">
<table>
<thead>
<tr scope="col">
<th>First name</th>
<th>Last name</th>
<th>E-mail</th>
<th>Approve</th>
</tr>
</thead>
<% #users.each do |user| %>
<tbody>
<tr>
<td><%= user.firstname %></td>
<td><%= user.lastname %></td>
<td><%= user.email %></td>
<td class="ui checkbox">
<input type="checkbox" tabindex="0" class="hidden">
</td>
</tr>
</tbody>
<% end %>
</table>
</div>
<% end %>
The wiki says it that it provides a simple way to approve users, but their view code actually just provides a simple way to list all users. I'm assuming that I need to use a form helper.
I made a custom admin controller specifically for an admin control panel and put all of the tools in an index page. You can probably do it a number of ways, though.
The common consensus on this seems to be that if you switch #users = User.find_by_approved(false) to #users = User.where(approved: false), it works better. That's what I currently have and it works very well.
I had this problem as well, and I ended up scrapping devise and making a custom user sign in method. You should be able to make it work, though. I followed the tutorial here and it helped immensely. Basically, you want to create a method which will approve users in your admin controller. This is the one I used:
`
def approve
User.where(id: params[:user_id]).update_all(approved: true)
redirect_to admin_index_path
end
From there, you add a put method to your routes.
put 'approve_admin', to: "admin#approve", as: :approve_admin
Finally, wrap your list of users in a form tag and add a hash of all of the user IDs you want to update as a hash.
<%= form_tag(approve_admin_path, method: :put) do %>
<% for user in #unapproved_users %>
<tr>
<td class="mdl-data-table__cell--non-numeric"><%= check_box_tag "user_id[]", user.id %></td>
<td><%= user.name %></td>
<td><%= user.email %></td>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag "Mark as approved", class: 'mdl-button mdl-js-button mdl-button--raised approve' %>
<% end %>
I made a method for approving users and another for unapproving users so I switched up the #users.each iteration in favor of a for iteration. I added #unapproved_users to my index method to make this work properly. Hope this works for you!
Related
As working on the Active Record as i have work on different function for active reocrd like Avg, sum and count as it display working fine and also Chart,
but one things is baffle me and i still cannot get it working and it should be working fine, as i cannot get display all data list table like
<table id="dttb" class="table table-hover">
<thead>
<tr>
<th> full name </th>
</tr>
</thead>
<tbody>
<tbody>
<% #user.each do |user| %>
<tr>
<td><%= user.fullname %></td>
</tr>
<% end %>
</tbody>
</tbody>
</table>
as it should be working as the error is kept displayed
undefined method `each' for nil:NilClass
as I look up information and most of them are mention .each do, seems I am doing wrong as I have used
<%= User.count(:user) %>
and
<%= column_chart User.group(:provider).count(:user) %>
and it seems working fine as query function.
so I tried again with find_each
<% User.find_each do |user| %>
<tr>
<td><%= puts user.fullname %></td>
</tr>
<% end %>
and the error is gone but it does not display at the data and it's show blanks unless I put 'link_to' but they keep display like
and I have put on AdminController.rb
class AdminController < ApplicationController
before_action :authenticate_user!
def index
#user = User.all
#tools = Tool.all
end
end
seems I miss something, I have look google or stackover flow, most of them answer are very same as this code as I wrote
Update: as I am able to get some data like a phone number or email
Here is code i wrote
<% User.find_each do |user| %>
<tr>
<td><%= link_to user.id, user %></td>
<td><%= link_to user.email, user %></td>
<td><%= link_to user.created_at.strftime('%v'), user %></td>
<td><%= link_to user.fullname, user %></td>
<td><%= link_to user.phone_number, user %></td>
</tr>
<% end %>
but frustration with fullname as it should be displayed but it not
Set #user (or better #users) in the controller:
def index # or the actual action name
#users = User.all # or User.order(:fullname)
end
I generated a devise model User, and I also have a Conversation controller. I'm showing all users, except the logged in one, and I'm trying to create a new Conversation between user1 and user2, but I get redirected to the index method of the Conversation Controller, not the create one. I understood from this link that making a post from one controller to another is a bad idea Rails: How to POST internally to another controller action?.
I've also tried to make a send_message method inside the Users controller and define it as a post in routes, but I get redirected to the show method of the Users controller.
What is the clean way of doing this?
class UsersController < ApplicationController
before_action :authenticate_user!
def index
#users = User.where.not(id: current_user.id)
end
def send_message
# #conversation = Conversation.new(conversation_params)
# if #conversation.save
#
# end
end
end
index.html.erb
<div class="col-xs-12 col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1> User's index </h1>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Email</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.email %></td>
<td><%= time_ago_in_words(user.created_at) %> ago</td>
<td>
<div class="btn-group">
<%= link_to 'Send', conversations_path(sender_id: current_user.id, recipient_id: user.id) %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
Edit:
private
def conversation_params
params.require(:conversation).permit(:sender_id, :recipient_id)
end
<ActionController::Parameters {"_method"=>"post", "authenticity_token"=>"394MDmcVVelccU//8ISYeqmk146exYc6G7SrrAhbCA/yQ/K8KTpSn/0EkXlZ4hB/g==", "recipient_id"=>"1", "sender_id"=>"3", "controller"=>"conversations", "action"=>"create"} permitted: false>
By default link_to helper sends GET request. You can do it with adding method: :post to its options.
<%= link_to 'Send', path, method: :post %>
You could redirect to new_converstion_path instead of conversations_path. And link by default sends GET not POST request.
ROR newbie. I have read a lot, but I think I'm slow to absorb. I'm trying to create a web app with two different views of the same content:
A page full of artworks for visitors to browse by image (at the root of the site).
A page with a table listing out those same artworks and showing all the relevant attributes I've defined for them (medium, etc.) so I can review data associated with each artwork. This is supposed to be my super-lightweight admin page.
My questions are:
Since I generated this site from a scaffold, I'm currently using views/artworks/index.html.erb as the admin table view (supposed to be private), and I created a 'home' page and added some code to the 'home' view (and pages_controller) to make the artworks show up there (for the public). Am I doing this right? Is this a good method of organization?
I've installed devise and successfully hidden links for editing artworks on the page behind a sign in, but I don't know the proper way to cordon off portions of the app (e.g. the admin table page, edit pages, etc.) from the rest of the world. Should I be putting these pages in a different folder? How do I make these pages private?
Here are some snippets:
home.html.erb
<div id="artworks" class="transitions-enabled">
<% #artworks.each do |artwork| %>
<div class="box">
<%= link_to image_tag(artwork.image.url(:medium)), artwork %>
</div>
<% end %>
</div>
artworks/index.html.erb:
<div class="row">
<div class="col-xs-6 col-sm-8 col-md-4">
<h1>Listing artworks</h1>
</div>
<div class="col-xs-4 col-sm-2 col-md-2 col-md-offset-6">
<%= link_to 'New Artwork', new_artwork_path, class:"btn btn-default" %>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Image</th>
<th>Title</th>
<th>Genre</th>
<th>Category</th>
<th>Medium</th>
<th>Date</th>
<th>Dimensions</th>
<th>Availability</th>
<th>Rating</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
<% #artworks.each do |artwork| %>
<tr>
<td><%= link_to image_tag(artwork.image.url(:thumb)), artwork %></td>
<td><%= artwork.title %></td>
<td><%= artwork.genre %></td>
<td><%= artwork.category %></td>
<td><%= artwork.medium %></td>
<td><%= artwork.date %></td>
<td><%= artwork.height %> x <%= artwork.width %></td>
<td><%= artwork.availability %> </td>
<td><%= artwork.rating %> </td>
<td><%= link_to 'Edit', edit_artwork_path(artwork) %></td>
<td></td>
</tr>
<% end %>
</tbody>
</table>
</div>
both pages_controller.rb and artworks_controller.rb have code like this:
def index
if params[:tag]
#artworks = Artwork.tagged_with(params[:tag])
else
#artworks = Artwork.all
end
end
pages_controller.rb:
def home
#artworks = Artwork.all
end
and the routes.rb:
get 'tagged' => 'artworks#index', :as => 'tagged'
devise_for :users
# get "artworks" => "artworks#index"
# post "artworks" => "artworks#index"
root "pages#home"
get "about" => "pages#about"
#get "users" => "users#index"
resources :artworks
Thanks in advance for your patience and help!
This can be the right way. But you have installed devise and hidden the links. But someone can directly hit the url. You need to add some authorization code which will take care that only admin user can edit the artworks. This can be done in many ways. If you have a simple application you can just add a before filter in which you can check if the user is admin then only he can access the page and call that on edit and update action. Either you can also use any authorization gem like Authority or so if it needs many roles. Hope this helps.
For making the code DRY:
before_filter :set_artworks, :only => [:home, :index]
private
def set_artworks
#artworks = Artworks.all
end
artworks/index.html.erb
<div class= 'row'>
<!-- your other source code goes here -->
</div>
You want this page to be private until the user is logged in. Then you can try this :
<% if current_user.present? %>
<div class= 'row'>
<!-- your other source code goes here -->
</div>
<% end %>
This div will be visible only if the user is logged in. for not yet signed in users this page will be private.
In order to make the edit option private :
<% if current_user.present? %>
<div id="artworks" class="transitions-enabled">
<% #artworks.each do |artwork| %>
<div class="box">
<%= link_to image_tag(artwork.image.url(:medium)), artwork %>
</div>
<% end %>
</div>
<% end %>
In any case if you want to public/private few sections then just wrap it inside the conditional if statements for views.
Still if anyone wishes then he can hit the url and enter into your action directly, in that case you can put condition in the controller.
before_action :authenticate_user!, only: [:action_1, :action_2]
Further if you need to keep things private on basis of user role, you can
always chose for cancan gem.
The simplest way of maintaining privileges is using cancancan gem.
Install it via bundler and generate model via rails generate cancan:ability. Then you have to distinguish admin users from others (e.g you can add integer "role" to User model) and write something like this in models/ability.rb#initialize
if user.admin?
can :manage, :all
else
can :read, Artwork
end
and modify controllers like this:
def index
authorize! :edit, Artwork
if params[:tag]
#artworks = Artwork.tagged_with(params[:tag])
else
#artworks = Artwork.all
end
end
This will throw an exception if not admin user will want to go to index. You can use redirect_to to inform user about that error. Add this to ApplicationController:
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
I'm creating a twitter-copy and right now I'm trying to get all the posts from all the users you follow and then show them on the home page. I've done this in PHP before, but I'm new at RoR so I might be trying to do this the wrong way.
a User has many Subscriptions
and a Subscription belongs to User
a User has many Posts
and a Post belongs to User
This is what i've got so far:
session_controller.rb
def get_posts
#sub = #current_user.subscriptions.first
Post.where("user_id = ?", #sub.following_id).find_each do |tweet|
render partial: 'shared/tweet', locals: {tweet: tweet}
end
end
I know .first gets only the first subscription, but I wanted to try to get just something out.
home.html.erb
<table>
<tr>
<th>Username</th>
<th>Tweet</th>
</tr>
<%= yield %>
</table>
_tweet.html.erb
<div class="tweet">
<td>Username here somehow</td>
<td><%= tweet.content %></td>
</div>
But right now nothing is coming up in the table.. So, what am I doing wrong? (am I doing anything right at all?)
Try this:
session_controller.rb
def get_posts
#sub = #current_user.subscriptions.first
#tweets = Post.where("user_id = ?", #sub.following_id)
end
home.html.erb
<table>
<thead>
<tr>
<th>Username</th>
<th>Tweet</th>
</tr>
</thead>
<tbody>
<% #tweets.each do |tweet| %>
<%= render 'shared/tweet', tweet: tweet %>
<% end %>
</tbody>
</table>
_tweet.html.erb
<tr class="tweet">
<td><%= tweet.user.name %></td> # Not sure
<td><%= tweet.content %></td>
</tr>
EDIT:
To get all the tweets for all the subscritions:
following_ids = #current_user.subscriptions.map(&:following_id)
#tweets = Post.where(user_id: following_ids)
I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand