Processing button on a Show view in Ruby on Rails - ruby-on-rails

I have an application entity called Source on my app. This entity has a property called url.
I want to make a processing on my SHOW view. So I added a button on the show view to make a call to my controller and do this processing.
This is my routes.rb
get '/process', to: 'sources#read', as: 'read'
This is my controller method:
class SourcesController < ApplicationController
before_action :set_source, only: [:show, :edit, :update, :destroy, :read]
access all: [:index, :show, :new, :edit, :create, :update, :destroy, :read], user: :all
def read
require 'rss'
require 'open-uri'
url = #source.url
open(url) do |rss|
feed = RSS::Parser.parse(rss)
puts "Title: #{feed.channel.title}"
feed.items.each do |item|
puts "Item: #{item.title}"
puts "Link: #{item.link}"
puts "Description: #{item.description}"
end
end
render template: 'rss_reader/home'
end
And of course. My show.html.erb:
<%= button_to 'Process Source', read_path(#source), method: :get %>
<%= link_to 'Edit', edit_source_path(#source) %> |
<%= link_to 'Back', sources_path %>
</div>
When I press the "Process Source" button, it goes to the right controller method, but the object #source its not being found because of:
Couldn't find Source with 'id'=
# Use callbacks to share common setup or constraints between actions.
def set_source
#source = Source.find(params[:id])
end
What Im doing wrong here?

You are visiting the route with read_path(#source) which is expected to set the param id to the value #source.id, but you did not define your routes to support any parameter in the path.
I believe read is an action that belongs to a single instance of Source. So, you should define the route on member. This way you will be able to access params[:id] in your controller and your before_action set_source will work fine.
Change your route definition to:
resources :sources, only: [...] do # Keep the `only` array just as you have now.
get '/process', to: 'sources#read', as: 'read', on: :member
end

Related

How to show edit link only in show view using ActiveAdmin

I want to show the link in the show view of ActiveAdmin. But it should not show up in the grid of the index view. I can't figure out how to do this. I've already tried quite a few approaches.
attempt 1
actions :all, except: proc{ params['id'].present? ? [:new, :destroy] : [:new, :destroy, :edit] }.call
this fails with undefined local variable or method 'params'
attempt 2
actions :all, only: :show, except: [:new, :destroy, :edit]
action_item only: :show do
link_to 'Edit Cash Out', "/admin/documents/#{params['id']}/edit" if params['id']
end
this fails because the route isn't being created for the edit path
attempt 3
actions :all, except: [:new, :destroy].tap do |a|
a << :edit unless params['id'].present?
end
fails with no block given
If I am not mistaken, you only want to hide the link to the edit action in the index page (in the grid).
If this is correct, one possible solution is included in this answer:
possible solution
index do
column :actions do |item|
links = []
links << link_to('Show', show_item_path)
links << link_to('Delete', delete_item_path, method: :delete, confirm: 'Are you sure?')
links.join(' ').html_safe
end
end
Just keep in mind to adjust the aforementioned code to fit the routes and naming.
Hope this works for you.
Can you please try below code?
actions :all, only: :show, except: [:new, :destroy, :edit]
action_item :view, only: :show do
link_to 'Edit Cash Out', "/admin/documents/#{params['id']}/edit" if params['id']
end

Two routes for the same action Rails

I have an application that lists all the subaccounts under a main account. However when I click the subaccount, instead of going to do accounts/1/subaccounts/1 I want it to go to subaccounts/1. When I use the for_each statement I get the following error. How can I click on a nested route and have it go to just subaccounts/1 instead of accounts/1/subaccounts/1?
<% #subaccounts.each do |sa| %>
<%= link_to "#{sa.name}", subaccount_path(sa) %>
<% end %>
Routes.rb
resources :subaccounts
resources :accounts do
resources :subaccounts
end
Subaccounts controller
before_action :set_account, only: [:show, :edit, :new, :create]
before_action :set_subaccount, only: [:show, :edit, :update, :destroy]
def show
end
private
def set_account
#account ||= Account.find(params[:account_id])
end
def set_subaccount
#subaccount ||= #account.subaccounts.find(params[:id])
end
def subaccount_params
params.require(:subaccount).permit(:name, :state)
end
The issue you are facing is due to same controller action for 2 different routes. You can fix it by either adding another controller for nested route
resources :accounts do
resources :subaccounts, controller: 'accounts_subaccounts'
end
Or handle exception and check for #account (least preferred way / bad practice)
#account ||= Account.find(params[:account_id]) rescue nil
With handling with rescue you need to handle #account everywhere.
You can also trigger set_account method when params[:account_id].present? which will also work for you.

How can I pass an id of one object to the controller of another object?

I know this has been asked but no solution has worked.
I'm trying to pass a group id to a procedure controller so I may make that procedure belong to that group.
Group Show View:
<%= link_to 'Create a Procedure', new_procedure_path(:group => #group.id), class: 'btn btn-default btn-small' %>
Procedure controller:
def new
#procedure = Procedure.new
#group = Group.find(params[:group])
Routes :
resources :groups, only: [:new, :create, :show, :destroy]
resources :procedures
If group_id is required, make it part of the url and won't need it in the form view. You'll have group_id in the params: params[:group_id] is what the controller should expect.
resources :groups, only: [:new, :create, :show, :destroy] do
resources :procedures
end
In your controller, do this:
def new
#group = Group.find(params[:group_id])
#procedure = #group.procedures.new
end
And you'd link to the new page like this
<%= link_to 'Create a Procedure', new_group_procedure_path(#group), class: 'btn btn-default btn-small' %>
To further add to Swards answer, you're looking at nested resources...
#config/routes.rb
resources :groups, except: [:edit, :update] do
resources :procedures #-> url.com/groups/:group_id/procedures/new
end
--
When you send a request to your server, you're requesting a "resource".
As defined by the HTTP spec,
The client submits an HTTP request message to the server. The server, which provides resources such as HTML files and other content, or performs other functions on behalf of the client
This is why the Rails routes have resources directives.
In your case, the resources you're requesting need to be dependent on another "parent" resource, hence you'd use the "nested" pattern. This provides a parameter of the "parent" var in your dependent controller:
#app/controllers/procedures_controller.rb
class ProceduresController < ApplicationController
before_action :set_group
def new
#procedure = #group.procedures.new
end
private
def set_group
#group = Group.find params[:group_id]
end
end
--
Your linking method would work from Swards recommendation; you may also benefit from polymorphic_path:
<%= link_to 'Create a Procedure', new_polymorphic_path([#group, :procedure]), class: 'btn btn-default btn-small' %>

how to view the page through the admin panel?

please help solve the problem.
a resource documents and the appropriate controller:
class DocumentsController < ApplicationController
def index
#documents = Document.all.paginate(page: params[:page], per_page: 10)
end
def admin_index
#documents = Document.all.paginate(page: params[:page], per_page: 10)
render layout: "admin"
end
def show
#document = Document.find(params[:id])
end
def admin_show
#document = Document.find(params[:id])
render layout: "admin"
end
....
....
end
a 2 layouts:
application.html.erb,
admin.html.erb
the controller index lists the documents in the public section (application.html.erb).
admin_index controller displays a list of documents in the closed part of the site (admin.html.erb).
in the public part of the site I can look any document by clicking on 'show':
<% #documents.each do |document| %>
<%= document.title %>
<%= link_to 'Show', document %>
<% end %>
The problem is that in a closed part of the site I did not get to see any document by clicking the link below:
<%= link_to 'Show', document %>
a problem that throws me a page of a particular document, but the layout: application.html.erb, and I need a layout: admin.html.erb
routes:
Testpager::Application.routes.draw do
get "admin/index"
resources :news, only: [:index, :show]
resources :documents, only: [:index, :show, :destroy]
get "contacts/index"
get "services/index"
get "index/index"
get "admin/index"
get "admin/documents" => 'documents#admin_index'
get "admin/documents/:id" => 'documents#admin_show'
root 'index#index'
end
First of all, there's no difference in the link you've created with the link_to helper in your index.html.erb and admin_index.html.erb, so let's address that first.
Change your admin_show route in your routes.rb to:
get 'admin/documents/:id', to: 'documents#admin_show', as: 'admin_document'
Now change the link_to in your admin_index.html.erb to this:
<%= link_to 'Show', admin_document_path(document) %>
That should do it.
Side note
The way you've set up the 'public' and 'admin' parts of your site seem odd. I would personally create an admin namespace and a separate DocumentsController in that namespace. You'll have to change your routes.rb, create an admin controller, view and layout if you want this.
Add the documents resource to the admin namespace instead of the admin routes you've already added:
...
namespace :admin do
resources :documents, only: [:index, :show, :destroy]
end
resources :documents, only: [:index, :show, :destroy]
...
Create a app/controllers/admin/documents_controller.rb file and move the admin_* methods from your original controller to that one and also move the admin_*.html.erb views to app/views/admin/*.html.erb.
Now, last but not least move your app/views/layouts/admin.html.erb file to app/views/layouts/admin/application.html.erb. That should do it.
Note that you've got to use a module in your admin controller:
module Admin
class DocumentsController < ApplicationController
...
end
end

ReNesting Resource Routes in Rails

So I just made one of my objects a nested resource of my user object. Now all of my links don't work and my index won't show. I am getting the error:
/views/photos/index.html.haml where line #8 raised:
No route matches {:action=>"show", :controller=>"photos", :id=>nil,
:user_id=>nil} missing required keys: [:id, :user_id]
with this line being where its finding the issue:
= link_to photo.title, user_photo_path(#user, #photos)
This is my controller for my photos object:
class PhotosController < ApplicationController
before_action :find_photo, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :authenticate_user!, except: [:index, :show]
def index
#photos = Photo.all.order(:cached_weighted_score => :desc)
end
def show
#comments = Comment.where(photo_id: #photo)
#photo = Photo.find(params[:id])
end
My routes look like this:
Rails.application.routes.draw do
devise_for :users
root 'photos#index'
resources :users do
resources :photos do
member do
get "like", to: "photos#upvote"
get "unlike", to: "photos#downvote"
end
resources :comments
end
end
end
This is my user controller:
class UsersController < ApplicationController
def show
#user = User.find_by(params[:id])
#photos= #user.photos.order(:cached_weighted_score => :desc)
end
end
finally the view that is generating the error code:
.container
.row
.col-lg-12
%h1.page-header Most Popular Photos
- #photos.each do |photo|
.thumbnail.col-lg-3.col-md-4.col-xs-6.thumb
%h2
= link_to photo.title, user_photo_path(#user, #photo)
= link_to (image_tag photo.image.url(:small)), photo
%p
= photo.get_likes.size
Likes
= link_to "Add New Photo", new_photo_path
Any help is appreciated. My last change was adding the photos route into below the users route.
2nd arg needs to be a photo instance from the loop not #photo which is probably nil:
= link_to photo.title, user_photo_path(#user, photo)
UPDATE 1: You also need to load up #user in PhotosController#show:
#user = User.find_by(params[:user_id])

Resources