Using a member route like this similar to one I have used for deleting tags:
resources 'factory' do
resources 'tags' do
member do
delete :remove
end
end
resources 'project_files' do
member do
delete :remove
end
end
end
I (should) invoke in the projects controller:
class ProjectFilesController < ApplicationController
def remove
#factory = Factory.find(params[:fabmoment_id])
#project_file = ProjectFile.find(params[:id])
authorize #factory, :project_file?
#project_file.remove!
head :ok
end
end
Which I can't check for correctness (yet). The partial _project_files looks like:
<li class="project_file">
<% if policy(factory).project_file? %>
<%= link_to "<span></span>".html_safe,
remove_factory_project_file_path(factory, project_file), method: :delete, remote: true,
class: "remove",
title: "remove" %>
<% end %>
<%= link_to File.basename(project_file.url), project_file.url %>
(<%= number_to_human_size(project_file.file.size) %>)
</li>
Which is invoked by passing locales with a render method in the factory#show view. (Could also add an index.)
Like this it is mostly equal to the tags remove action though and I like to keep things consequent and simple.
The error I receive from my spec:
No route matches [DELETE] "/factories/1/project_files/%2Fuploads%2Ffactory%2Fproject_files%2F1%2Fthe_puritan_1st_floor.stl/remove"
My Factory model only contains mount_uploaders :project_files, ProjectFileUploader
Any ideas on how to make this work?
Related
I have a question about acts_as_taggable_on. I'm making a BBS and want to display link tags. However, my website can display only strings not links. So I want to put link to strings.
I want to link_to each tags#show.
Now some tags are saved in Tag table and this table have these column(id, name, created_count)
This is my code:
post.rb
def save_tags
array = self.check_taggable_word(self.title)
self.tag_list.add(array, parse: true)
end
def tag_lists
tag_lists = self.tag_list
end
def check_taggable_word(text)
ary = Array.new
nm = Natto::MeCab.new
nm.parse(text) do |n|
ary<<n.surface
end
tags = ActsAsTaggableOn::Tag.pluck(:name)
return ary & tags
end
show.html.erb (post)
Tag:
<% #post.save_tags %>
<%= #post.tag_list %>
posts_controller.rb
def show
#post = Post.find(params[:id])
#category = #post.category
end
routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/about' => 'static_pages#about'
get '/contact' => 'static_pages#contact'
resources :categories do
resources :posts
end
resources :posts do
resources :comments
end
resources :tags, only: [:index, :show]
end
It is not so sure what you are trying to achieve, and it might help if you post your controller , too.
However, displaying links can be achieved in rails by using the link_to helper
<% = link_to 'text', some_path %>
Your target is to connect the link to your controller action where you handle the 'tags'
The gem you mentioned gives you another example of displaying links in views. This might work for your depending on your naming conventions in your controller.
<% tag_cloud(#tags) do |tag| %>
<%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => 'css_class' %>
<% end %>
In general: you need to call
#tags = Tags.all
somewhere in your controllers to get all entries for the tags. Than you can loop over tags which each...that can produce you a link of all your tags and if you want to link to tags#show the link must go to an action where you find that specific tag. For example this can be in that action:
#tag = Tag.find(params[:id])
. That's it.
OK i edit once again. TRY:
in you post controller#show you can show all tags for that post like so
#post.tags.each do |tag|
<%= link_to tag.name, tag %>
this requires that your tag has attribute "name"
in your post#index you can do
<%#post.each do |post|%>
<%post.tags.each do |tag|%>
<%= link_to tag.name, tag %><%end%><%end%>
if you just want all tags to be displayed without post etc. TRY:
in your controller posts#index
#tags = Tag.all
<%#tags.each do |tag|%>
<%= link_to tag.name, tag %><%end%>
In your current controller action posts#show you will only find the tags for that #post because all you do is finding the post by id. So you will only find tags for that post if the association is correct.
That allows you to do #post.tags.each do |tag|...etc.
tag than can be used for the link_to helper.
If you use
<%= link_to tag.name, tag %>
it will show you a link with the tag.name that links to that specific tag for each tag that belongs to the post.
I am new to rails and trying to figure out how to pass id from view to controller. I have create below routes.rb file i didnt want resources here just to have better understanding of how to pass params
Rails.application.routes.draw do
get 'sites/edit/:id', to: 'sites#edit'
get 'sites/main'
devise_for :users
root 'sites#main'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
below is my controller
class SitesController < ApplicationController
def main
#site = Site.all
end
def edit
#site = Site.find(params[:id])
end
private
def site_params
params.require(:site).permit(:title, :subtitle,:name)
end
end
and i have two views for my site controller. In main.html.erb
<h1>Sites#main</h1>
<p><%= current_user.email %> user is signned in </p>
<%= #site.each do |temp| %>
<p><%= temp.name %></p>
<p></p>
<p></p>
<%= link_to "Edit Site", sites_edit_path(#temp) %>
<% end %>
I am not able to link it to correct controller.
First: your edit routes should not be
get 'sites/edit/:id', to: 'sites#edit'
Instead it should be get 'sites/:id/edit' => 'sites#edit'
Second: your link to method should not be
<%= link_to "Edit Site", sites_edit_path(#temp) %>
instead it should be <%= link_to "Edit Site", sites_edit_path(temp) %>
You can get to know about your routes from terminal by doing rake routes or If you want a browser view then
http://localhost:3000/rails/info/routes
You need to replace
<%= link_to "Edit Site", sites_edit_path(#temp) %>
to
<%= link_to "Edit Site", sites_edit_path(temp) %>
You have the variable temp not #temp
Also, As sarcastic suggested you need to change the route entry to
get 'sites/edit/:id', to: 'sites#edit', as: :sites_edit
I am relatively new to Rails, I am trying to create a cookbook app/site from scratch, I'm not following any tutorials or anything like that. Anyway... I am still in the early stages of the site but I am now to the part where I am wanting to display a index list of all the different kinds of recipes. But I want to filter the list, for example:
If I click on the 'vegetables' button on the navigation bar I would like to be take to an index page that only displays the different vegetable recipes.
I've gone ahead and added a string attribute to Recipes, called "category" thus I will be able to differentiate between Meat, Seafood, Poultry, Appetizers and Vegetable recipes. My goal is to only need the one controller 'recipes' and in the index action be able to conditionally filter on a param. Thus filtering the list by 'category' of food. But I am unsure how to go about doing so.
Here is my RecipesController:
class RecipesController < ApplicationController
def index
#recipes = Recipe.all
end
def show
#recipe = Recipe.find(params[:id])
end
def new
end
def edit
end
end
Here is my Routes file:
Rails.application.routes.draw do
resources :recipes
get 'vegetables' => 'recipes#vegetables'
get 'poultry' => 'recipes#poultry'
get 'meat' => 'recipes#meat'
get 'seafood' => 'recipes#seafood'
get 'appetizers' => 'recipes#appetizers'
devise_for :users
get 'about' => 'welcome#about'
root to: 'welcome#index'
end
Here is the application layout file that contains the navigation bar:
<!DOCTYPE html>
<html>
<head>
<title>Mrs. P's Cookbook</title>
<link href='https://fonts.googleapis.com/css?family=Mate+SC' rel='stylesheet' type='text/css'>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="top-banner">
<h1 class="banner-logo"> <%= link_to "Mrs. P's Cookbook", root_path %></h1>
<nav>
<%= link_to "POULTRY", poultry_path, class: "nav-link" %> |
<%= link_to "MEAT", meat_path, class: "nav-link" %> |
<%= link_to "SEAFOOD", seafood_path, class: "nav-link" %> |
<%= link_to "APPETIZERS", appetizers_path, class: "nav-link" %> |
<%= link_to "VEGETABLES", vegetables_path, class: "nav-link" %> |
<%= link_to "ABOUT", about_path, class: "nav-link" %>
</nav>
<% if current_user %>
Hello <%= current_user.email %>! <%= link_to "Sign out", destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to "Sign In", new_user_session_path %> or
<%= link_to "Sign Up", new_user_registration_path %>
<% end %>
</div>
<div class="white-field">
<%= yield %>
</div>
</body>
</html>
Here is my Recipe.rb model file:
class Recipe < ActiveRecord::Base
has_many :comments
end
Here is my Recipe table:
create_table "recipes", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "category"
end
I've got the different category views, Vegetables, Meat, Poultry, Seafood and Appetizers all inside the Recipe view folder. All of the views are empty except for some text that just says "Vegetable recipes will be listed here.", "Meat recipes will be listed here.", "Seafood recipes will be listed here.", etc..
I know what I am asking might be a tall order, so any help you guys can provide I will be extremely grateful for. If you need anymore information please let me know.
I came up with two possible solutions (among many! :) )
Solution 1
One solution could be using a query string. The routes file would be
Rails.application.routes.draw do
resources :recipes
devise_for :users
get 'about' => 'welcome#about'
root to: 'welcome#index'
end
Now create the links with the category as argument. In your view:
...
<nav>
['poultry','meat','seafood','appetizers','vegetables'].each do |category|
<%= link_to category.upcase,
recipes_path(category: category),
class: "nav-link" %> |
end
<%= link_to "ABOUT", about_path, class: "nav-link" %>
</nav>
...
And in the controller you can capture the category, querying the model as already showed in the other answers. For example
class RecipesController < ApplicationController
def index
#recipes = params[:category].blank? : Recipe.all :
Recipe.where(category: params[:category])
end
...
end
But isn't that elegant if you want to customize the view of a single category.
Solution 2
Add the following route, (before the resources :recipes )
Rails.application.routes.draw do
get 'recipes/:category' => 'recipes#category', as: :recipes_category
resources :recipes
...
end
Note that with the as: :recipes_category you can reference to this path using the recipes_category_path helper
Now we need to add the category action to the RecipesController
class RecipesController < ApplicationController
...
def category
#recipes = Recipe.where(category: params[:category])
end
...
end
And the the path in the link_to will change to
...
<%= link_to category.upcase,
recipes_category_path(category: category),
class: "nav-link" %> |
...
IMHO that's cleaner if you want to customize your view without caring the presence of the param and the url looks prettier :).
Looking forward
As already suggested by #denys281, the category field smells like a separate entity, related with the recipes with a N:1 relation.
The two model will have the associations
class Recipe < ActiveRecord::Base
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :recipes
end
In that way, for example, you can easily have all the categories by calling
Category.all
or the recipes for a category with
#category = Category.find(2)
#recipes = #category.recipes
It really depends on what you want to achieve. I hope I gave you some ideas on the argument.
Regarding the other suggestion of using Slim, I disagree. It's just syntactic sugar, it's not standard and it will confuse you: the most of the code you will find around will have the standard syntax.
Get your hands dirty before using some other tools, it will give you a better idea of the mechanisms behind, a better understanding if the tool will solve your needs and how you can customize it.
I suggest you to read the official rails guide, the countless blogs and articles and try to read code written by others ( thanks Open Source! ).
Use a named scope like this
class Recipe < ActiveRecord::Base
scope :by_category, lambda {|cat|
where(category: cat)
}
...
end
Then you can call
Recipe.by_category("Vegetables")
You can also do:
scope :vegetables, lambda {
where(category: "Vegetables")
}
and then call
Recipe.vegetables
I think you need use some tutorial, in this way you will see best practices and so on. Also I think you should read some good book about relational databases.
Use slim ;
Create Category table. Recipe belongs_to :category. Category has_many :recipes. Check association basics ;
How to get recipes you can look at Active Record Query Interface (Something like Recipe.where(category_id: params[:id])) ;
Also check about partials
Your routes should coincide with a function in your controller so when you have a route to 'recipes#meat', your controller would be looking for a 'meat' function and a 'meat' view
I would remove those routes and have one called
'get recipe/:recipe'
and pass that parameter(the string) to the show function.
This way you could access a specific recipe like so:
#recipes = Recipe.where("category = ?", params[:recipe])
For my projects I have the following relevant code
routes:
resources :lists do
resources :items
end
I now included a loop on list/show page in which I want to show the item and provide the users with the possibility to delete the item.
So i got code like this:
<% #items.each do |item|%>
<p>
Item: <%= item.name %>
<%= time_ago_in_words(item.created_at) %> ago.
</p>
<%= link_to "Delete", [#list.item, item], method: :delete %>
<% end %>
But when I try to run it I get the error:
undefined method 'item' for #<List:0x007fba7be6fe28>
While I did define the variables in my controller:
Items-controller:
def destroy
#list = current_user.list
#item = #list.items
end
Could anyone explain whats causing this error?
you have a typo in your controller - it should be #items = #list.items that's why the iteration doesn't work properly.
edit: after formatting your original question, I see that the error was raised on #list object, so you have to fix path to delete action:
<%= link_to "Delete", [#list, item], method: :delete %>
you build the path by providing the parent object (#list) and then the object itself (item) - Rails will translate it to list_item_path.
change your link_to
= link_to("Delete", lists_items_url(#list, #item), method: :delete)
You have defined resources :lists and resources :items.
Basically what you want to do is send a DELETE request to the collection with the IDs to fetch and delete the items.
Run a rake routes to check the exact naming, but I think it's written like that to be sure. Although you don't seem to be needing the IDs based on your controller's action, you still need to supply them for the helper.
You're using #items.each and in your controller have only #item.
I'm trying to destroy links that belong to a category model (through my browser). I can successfully delete a link that has an id of 1 and category_id of 1, but when I try to delete a link that has any other id I get hit with:
ActiveRecord::RecordNotFound in LinksController#destroy
Couldn't find Link with id=1 [WHERE "links"."category_id" = 1]
Very frustrating, because I'm not trying to delete a link that has an id of 1! But I see in the request parameters that it's always trying to delete a link with "category_id"=>"1",
"id"=>"1"}, no matter what link I click on. Looking at the links in my development database confirms they exist and have ids that are not 1...
Here's the code for LinksController#destroy:
class LinksController < ApplicationController
def destroy
#category = Category.find(params[:id])
#link = #category.links.find(params[:id])
#link.destroy
redirect_to category_url(#category)
end
Here's the code for the view where I'm trying to delete these pesky links:
<h1><%= #category.category %></h1>
<p><%= #category.description %></p>
<ul>
<% #category.links.each do |link| %>
<li>
<%= link_to link.title, link.url %> |
<%= link_to "delete", category_link_path(#category), :method => :delete %>
</li>
<% end %>
Edit: Added parameters
{"_method"=>"delete",
"authenticity_token"=>"[removed]",
"category_id"=>"1",
"id"=>"1"}
Edit: Added config/routes.rb:
LinkManager::Application.routes.draw do
resources :categories do
resources :links, only: [:create, :destroy]
end
root :to => 'categories#index'
What am I overlooking? Is there anything I can try?
Your call to category_link_path is ommitting something. Perhaps it should look like this?
<%= link_to "delete", category_link_path(#category, link), :method => :delete %>
It looks like you're fulfilling the category_id part of the route by passing in #category, but you also need to provide link as the id.
Then you need to fix your destroy action as such:
def destroy
#category = Category.find(params[:category_id])
#link = #category.links.find(params[:id])
#link.destroy
redirect_to category_url(#category)
end
On your category_link_path you should be passing your category as well as your link. something like
category_link_path(#category, link)
Also, on your controller, to find your category it should look like Category.find(params[:category_id]