My app uses devise and devise_invitable to handle invitations. On my new invitations view I have a table that lists all users that have been invited. I want to add a column to delete each listed user. If I understand correctly, the route expects a format that should probably be something like remove_user_invitation_path(something) and also that it appears to be an invitation_token (an attribute of the User model). I just don't know how to insert it into the URL as a format. I'm also not sure if this will delete the user itself or the invitation (* I placed the) given that a user can accept or ignore an invitation, I worry that it will only work for users that have a pending invitation. Any input is appreciated!
$ rails routes
remove_user_invitation GET /users/invitation/remove(.:format) users/invitations#destroy
# users/invitations/new
<% #invited_users.each do |invited| %>
<tr>
<td><%= invited.email %></td>
<td><%= link_to "Delete", remove_user_invitation_path, method: :delete, data: { confirm: "Are you sure you want to delete this user?" } %></td>
<tr>
<% end %>
# GET /resource/invitation/remove?invitation_token=abcdef
def destroy
resource.destroy
set_flash_message :notice, :invitation_removed if is_flashing_format?
redirect_to after_sign_out_path_for(resource_name)
end
# What my variable contains
#invited_users = User.where.not(invitation_sent_at: nil)
Related
Hello I have a lists of invoices that belong to a business and also the business belongs to a user, I am trying to have a button (link to) on a table in which all the invoices are listed for the user to be able to update the status of the invoice.
Pretty much if the user hits the link it will change from paid: true to paid: false and viseversa.
here are the routes:
resources :businesses do
resources :invoices
end
Here is the section of the table in which the link is:
<% if invoice.paid %>
<td><%= link_to "Mark as Not Paid", business_invoice_path(current_user, invoice), method: 'put', data: {paid: false} %></td>
<% else %>
<td><%= link_to "Mark as Paid", business_invoice_path(current_user, invoice), method: 'put', data: {paid: true}%></td>
<% end %>
Note: The paid column is a boolean on the db
Since, the paid column is present on Invoice, it is much better if you handle it at the controller or model level instead of getting the value from the form.
Remove if else conditions and combine it as below:
<%
invoice_text = invoice.paid ? 'Mark as Not Paid' : 'Mark as Paid'
%>
<td><%= link_to invoice_text, business_invoice_path(invoice), method: :put %></td>
In the Business::InvoicesController you can write the logic in update like this:
Business::InvoicesController < ApplicationController
before_action :authenticate_user!
before_action :set_invoice
def update
# TODO: find the business using the invoice
# have a check in place to authorize the
# transaction (if invoice belongs a business which
# belongs the current_user or not, if not then raise Unauthorized error)
# if business does belongs to the current_user then proceed to next step
# invert the value of paid column based on existing value
#invoice.update(paid: !#invoice.paid)
end
private
def set_invoice
#invoice = Invoice.find(params[:id])
end
end
With logic above, you can forget about maintain/finding the value of paid column since you have an option to revert the value of paid to true and back to false. Also, that I assumed you are using Devise for authentication.
I am trying to display only the rows that belong to certain states in my application. I can do it the long way in Javascript, but I would prefer to better understand Rails and queries in the controller. I want to take the users to another page and then show them only that the companies in that state. It would be great to not have to link them to another page. Does anyone know how to do this?
Here is what I have in my controller
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(params[:state])
end
My route
get '/vendors/:state', to: 'collectives#vendors'
Then I use the stereotypical method to print a table in a html.erb file.
<% #vendors.each do |company| %>
<tr>
<td><%= company.name %></td>
<td><%= company.state %></td>
etc...
Should your controller code change the where as follows:
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(state: params[:state])
end
or better:
def vendors
#vendors = Collective.where(sort: 'Vendor', state: params[:state])
end
Using sessions instead of url params.
This is more or less what you can do, sorry if it is not completly working for your case, just to give an idea.
# view collectives/index (or whatever you have)
<%= form_tag (controller: :collectives, action: :set_status_filter, method: :post) do %>
<%= select_tag(:session_status_filter, options_for_select(#your_list_of_options_for_the_filter)) %>
<%= submit_tag "Set filter" %>
<% end %>
# collectives controller
def index # or whatever, this is the page containing the form and the list to show
#vendors = Collective.where(sort: 'Vendor').all
if session[:session_status_filter] == # etcetera
then #vendors = #vendors.where(state: session[:session_status_filter]) # for example
else # another option just in case, etcetera
end
end
def set_status_filter # this action is called by the form
session[:session_status_filter] = params[:session_status_filter]
respond_to do |format|
format.html { redirect_to *** the view where the form is placed ***, notice: 'the filter is set to: ....' + session[:session_status_filter] } # after the session variable is set the redirects goes to index which uses the session to filter records
end
end
params[:session_status_filter] is passed by the form to collectives#set_status_filter. The value is used to set the session variables. After that the action collectives#set_status_filter redirects to the index, or whatever page you placed the form and the list to show.
I've been borrowing some code from an old ruby on rails 3 app of mine for a new rails 4 app. The code works on the old site, but on the new one it doesn't.
Here's my routes.rb:
scope ':username' do
resources :recipes
end
get "/:username" => "recipes#index"
Here's my controller index:
def index
#user = User.find_by_username params[:username]
#recipes = Recipe.all
end
and my view:
<% #recipes.each do |recipe| %>
<tr>
<td><%= recipe.name %></td>
<td><%= link_to recipe.name, recipe_path(username: #user.username, id: recipe.id) %></td>
<td><%= link_to 'Edit', edit_recipe_path(recipe) %></td>
<td><%= link_to 'Destroy', recipe, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
but the error pops up:
undefined method `username' for nil:NilClass
but the current user username is set to test so its not nil, and the error shouldn't be popping up.
Thanks for all help!
When you have variables that could be potentially be nil, you should handle the case where they are nil, unless you explicitly wish for it to fail in these circumstances.
The dynamic find_by methods return nil when no records are found. Hence, as alfonso pointed out, you are getting a null value for #user.
In this particular instance, I would question how you are using the username param; if recipes are associated with recipes, then I would set up a has_many :recipes in my user model, and belongs_to :user in my recipe model.
Since the user is the 'parent' here, I would opt to create a recipes action in the UsersController. It seems more logical to me to put the recipes that belong to a user in the user's controller, and access the recipes as a collection from the user.
Alternatively, if you are trying to show recipes associated with a user, I would put the action in the RecipesController, and get the user that belongs to a recipe by using the #user method set up from the belongs_to relationship in the database.
In either case, you'll want to guarantee that the users and/or any recipes are defined before trying to render a page. You might want to display a 501 error or something similar if a user doesn't exist that's trying to be accessed, etc.
If you insist that there should always be a user for a recipe, then you should add that type of validation to the recipes model, so that adding a recipe without a user is disallowed:
validates :user, :presence => true
Sorry if I went a little off tangent.
get "/:username"
Here - :username is in position of id
#user = User.find_by_username params[:username]
Here you are trying to find it by params.
Link should look like this http://localhost:3000/user_name/user_name?username=user_name
to find some user, and it is obviously not what you want to achieve.
get "/:id" => "recipes#index"
#user = User.find(params[:id])
I have a strange BUG in a nested resources thing. I have a Seller/Car relationship where a Seller has_many Cars. Now I need to delete a Car from those that belong to a seller (the seller is authentication through Sessions#create and its id is stored in session[:seller_id]:
This is the Car Index View listing all cars that belong to this particular seller:
<%= #cars.each do |car| %>
<tr>
<td><%= car.brand %></tr></td>
<td><%= link_to 'Edit', edit_seller_car_path(session[:seller_id], car) %></td>
<td><%= link_to 'Destroy', seller_car_path(session[:seller_id], car) %></td>
</tr>
<% end %>
Standing on the Car index listing all cars belonging to the authenticated seller, the URL looks like localhost:3000/sellers/2/cars. This page displays the table listing cars with the edit and destroy buttons (edit works fine)
Here is the Cars#destroy:
#seller = Seller.find(params[:seller_id])
#car = #seller.cars.find(params[:id])
#car.destroy
flash[:notice] = "Deleted"
redirect_to seller_cars_url(session[:seller_id])
Here is the Cars#edit (it's working fine when editing):
#seller = Seller.find(params[:seller_id])
#car = #seller.cars.find(params[:id])
When I click on the destroy button, this BUG happens:
1) Strangely, the car is still deleted successfully.
2) I get routing error:
No route matches {:action => "edit", :controller => "cars", :seller_id=>nil, id=>#<Car id:23, brand:"Opel"...
Looks like the problem here arises in the Edit button in the index page. The car it's referring to is the first car in the table and the seller_id is nil here, meaning the seller_id is no longer held in session[:seller_id], which is the act of Sessions#destroy
3) I noticed that the Seller is logged out. As if the destroy in Car controller invokes the Destroy in Sessions controller that clears the session.
4) The URL seems to be the correct one for the Cars index: localhost:3000/sellers/2/cars, but I still see that routing error mentioned in 2.
I would appreciate if you please help guide me in this strange behavior. Thank you.
i was wondering how someone can pass hidden fields in a link_to performing a delete request. i have..
<%= link_to "delete", feed_item, method: :delete,
confirm: "You sure?",
title: feed_item.content,
user_id: user_id %>
<% end %>
ive been trying to pass user_id into my controller's destroy action but it cant seem to find params[:user_id]
it seems like its possible to pass hidden values when the method is a :post, but how can i do so in a :delete?
i essentially just want the user_id in my destroy action, so it can redirect back to the users profile page.
thank you
The proper way would be to either put feed_item under user resource or user current_user method in the controller
if you decide to put it under user resource the modify your routes file as
resources :users do
resources feed_items, :only=>[:destroy]
end
and than in your link to delete change the path to
user_feed_item_path
Alternatively if you have current_user method from using any sort of authentication solution you can just use that in your redirect path