No route error for nested resources in Rails - ruby-on-rails

Hi this is my first time using nested resources. I did rake routes and found a path to new_user_album_path, but it doesn't seem to work. Could the problem be because I did a double nest?
The problem is specifically when I click a link in my Users views file named show.html.erb . Trying to link to a "create an album" page but that's when it shows me an error:
No route matches {:action=>"new", :controller=>"albums"}
Here are my files:
show.html.erb
<% provide(:title, "Welcome, #{#user.name}!") %>
<div>
You currently have <%= pluralize(#user.albums.count, "album") %>
</div>
<div>
<%= link_to "Create a new album!", new_user_album_path %>
</div>
<div>
<% if #user.albums.any? %>
hey
<% else %>
boo
<% end %>
</div>
<%= link_to "Back", users_path %>
Config/routes
Pholder::Application.routes.draw do
resources :users do
resources :albums do
resources :pictures
end
end
Controller
class AlbumsController < ApplicationController
def index
#albums = Albums.all
respond_to do |format|
format.html
format.json { render json: #albums }
end
end
def new
#user = User.find(params[:user_id])
end
end

You need to pass the user to the route method, like:
new_user_album_path(#user)

Related

How do I connect routes to partials?

I am working on a rails app, where one of the tabs (the user show view) has a partial that is an inner navbar of sorts. There are three links (match, activity, message), each of which correspond to a different partial that is rendered to the right of the inner navbar.
Each of the partials has a corresponding route in my routes.rb file, but they are all rendered within one controller action (user#show). As a result, my inner navbar links alone are bringing the page to the proper route, but aren't successfully rendering the partials. To resolve this, I am checking within the view for what the end of the route is, and rendering the appropriate partial accordingly.
I imagine that there is a more ideal way to accomplish what I am looking to do, but I've had trouble figuring out what that might be.
I know that I could use separate view files instead of partials to resolve this, but for the sake of modularity, I would rather not move in that direction. Is there a better way for me to link routes to the appropriate partials?
routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
resources :messages
resources :replies
resources :posts
resources :organizations
resources :users
resources :sessions
resources :matches
root "welcome#index"
get "/users/:id/match", to: "users#show", as: "user_match"
get "/users/:id/activity", to: "users#show", as: "user_activity"
get "/users/:id/message", to: "users#show", as: "user_message"
end
users_controller
class UsersController < ApplicationController
skip_before_action :verify_authenticity_token, only: [:create]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:notice] = "Your account was created!"
redirect_to #user
else
flash[:alert] = #user.errors.full_messages.join(", ")
render 'new'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
/users/show.html.erb
<div class="row">
<% if #user.id == current_user.id %>
<div class="col-md-2 justify-content-start">
<div>
<ul>
<li>
<%= link_to(user_message_path(current_user.id)) do %>
<%= fa_icon "envelope", text: "Messages" %>
<% end %>
</li>
<li>
<%= link_to(user_activity_path(current_user.id)) do %>
<%= fa_icon "comments", text: "Activity" %>
<% end %>
</li>
<li>
<%= link_to(user_match_path(current_user.id)) do %>
<%= fa_icon "handshake-o", text: "Matches" %>
<% end %>
</li>
</ul>
</div>
</div>
<% end %>
<div class="col-md-10 justify-content-center">
<% last = request.path.split('/').last%>
<% if #user.id == current_user.id %>
<% if last == "match" %>
<%= render partial: "match" %>
<% elsif last == "activity" %>
<%= render partial: "activity" %>
<% elsif last == "message" %>
<%= render partial: "message" %>
<% else %>
<%= render partial: "home"%>
<% end %>
<% else %>
<%= render partial: "home" %>
<% end %>
</div>
</div>
You have a few alternative approaches you could take, like setting each sub-page up as a new controller (UserMatchesController, etc.) and routing to them directly, or using AJAX to load the sub-sections dynamically, but your approach isn't bad. What I would do to improve on it is to make the sub-page a named segment in the route with a constraint to lock it down:
get "/users/:id/:section", to: "users#show", constraints: { section: /^(message|home|match|activity)$/ }
You can link to each section by passing that parameter as an argument:
link_to user_path(current_user.id, section: "message")
And then in your template, something like:
render partial: params[:section]

My CREATE & DELETE routes not working do not understand why?

Hello I am trying to create a bookmark feature in my app. I have created the
model I want to bookmark (Hairstyle), I also have a User model and a "Saved_Hairstyle" model which is the join table in the scenario.
In my routes.rb file I added a CREATE & DELETE route. In my controller I wrote out the CREATE & DELETE methods. I then proceeded to link_to my CREATE & DELETE methods paths in my View.
I would like that when I click on the CREATE Link a POST method is fired so that I can show an element on the page as being "bookmarked" and when I click the DELETE link a DELETE method is fired so that I can show an element on the page as being "unboomarked" but they don't work.
When I do RAILS ROUTES in Rails C I can see the right pathways but when I click through the links don't do anything.
Repo for ease of understanding: https://github.com/Angela-Inniss/hair-do
routes.rb
Rails.application.routes.draw do
root to: 'pages#home'
devise_for :users
resources :hairstyles do
member do
put "like", to: "hairstyles#upvote"
put "dislike", to: "hairstyles#downvote"
end
resources :comments, only: :create
resources :saved_hairstyles, only: [:new,:create]
end
resources :saved_hairstyles, only: :destroy
resources :comments, only: :destroy
resources :hairdressers
end
class SavedHairstylesController < ApplicationController
def create
#hairstyle = Hairstyle.find(params[:hairstyle_id])
#saved_hairstyle = SavedHairstyle.new(user: current_user, hairstyle: #hairstyle)
if #saved_hairstyle.save
respond_to do |format|
format.html { redirect_to hairstyle_path(#saved_hairstyle.hairstyle) }
format.js # <-- will render `app/views/comments/create.js.erb`
end
else
respond_to do |format|
format.html { render 'hairstyles' }
format.js # <-- idem
end
end
end
end
def destroy
#saved_hairstyle = SavedHairstyle.find(params[:id])
#saved_hairstyle.destroy
#hairstyle = #saved_hairstyle.hairstyle
respond_to do |format|
format.html { redirect_to hairstyle_path(#saved_hairstyle.hairstyle }
format.js
end
end
view.html.erb
<div class="bookmark">
<% saved_hairstyle = SavedHairstyle.find_by(user: current_user, hairstyle: hairstyle.id) %>
<% if saved_hairstyle %>
<%= link_to hairstyle_saved_hairstyle_path(saved_hairstyle), method: :post do %>
<i class="fas fa-plus"></i>
<% end %>
<% else %>
<%= link_to saved_hairstyle_path(hairstyle), method: :delete do %>
<i class="fas fa-plus-circle"></i>
<% end %>
<% end %>
</div>
create.js.erb file (this is what I Would like to happen on the POST request (i have something similar for the DELETE request)
plusCircle = document.getElementById("bookmark");
plusCircle.innerHTML = `<%= link_to '#', method: :post do %>
<i class="fas fa-plus"></i>
<% end %>`
There seems to be some errors in your view logic. You are loading saved hairstyles and try to book mark it again. You're also trying to delete a saved hairstyle if it doesn't exist. The path helpers also seem to be wrong (delete method is not nested and nested resources should be plural). Maybe it should look something like this:
<div class="bookmark">
<% saved_hairstyle = SavedHairstyle.find_by(user: current_user, hairstyle: hairstyle.id) %>
<% if saved_hairstyle %>
<%= link_to saved_hairstyle_path(saved_hairstyle), method: :delete do %>
<i class="fas fa-plus-circle"></i>
<% end %>
<% else %>
<%= link_to hairstyle_saved_hairstyles_path(hairstyle), method: :post do %>
<i class="fas fa-plus"></i>
<% end %>
<% end %>
</div>
By the way, if you check your console, you probably will see some errors that would point you to the right direction. You should also move saved_hairstyle query to a helper method.

NoMethodError in Users#show (Ruby Rails)

I'm running into a NoMethodError in my Users#show when trying to include a form partial for submitting a task item (_form.html.erb). My other partial (_item.html.erb) is rendering properly. My item model and my user model are related to each other, user has_many :items, and item belongs_to :user.
Any and all help would be greatly appreciated!
Below is my routes.rb
Rails.application.routes.draw do
get 'welcome/index'
get 'welcome/about'
root 'users#show'
resources :users do
resources :items, only: [:new, :create]
end
devise_for :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Below is my terminal output
ActionView::Template::Error (undefined method `items_path' for #<#<Class:0x007fefeca61dd0>:0x007fefeca58b18>
Did you mean? items_create_path):
1: <h4> Create a new to-do item </h4>
2:
3: <%= form_for #item do |f| %>
4: <%= f.label :name %>
5: <%= f.text_field :name, class: 'form-control', placeholder: "Enter task here" %>
Items Controller
class ItemsController < ApplicationController
def new
#item = Item.new
end
def create
#item = Item.new
#item.user = current_user
#item.name = params[:item][:name]
if #item.save
flash[:notice] = "Item saved"
redirect_to #item
else
flash.now[:alert] = "Item was not created, please try again."
render :new
end
end
end
Users Controller
class UsersController < ApplicationController
def show
if !current_user.nil?
#user = current_user
#item = Item.new
#items = #user.items
else
redirect_to new_user_registration_path
end
end
end
Users#show page
<h2> Your to-do list</h2>
<div class="col-md-8">
<div class='items'>
<%= render partial: "items/item", local: { item: #item} %>
</div>
</div>
<div class="col-md-8">
<div class='new-item'>
<%= render partial: "items/form", local: { item: #item } %>
</div>
</div>
In your routes.rb file, you have items defined as a nested resource. You can check all of your routes by running this command on your terminal: rake routes.
For your routes specifically, you say:
resources :users do
resources :items, only: [:new, :create]
end
This would give you routes for GET /users/:user_id/items/new and POST /users/:user_id/items. However, in your form, it looks like you're trying to do this: <%= form_for #item do |f| %>. You don't have a route defined for an item by itself. You'll need to supply a user as well.
Try this for your form:
<%= form_for [#user, #item] do |f| %>
And something like this in your ItemsController:
class ItemsController
def new
#user = current_user
#item = Item.new
end
end
Your items route is nested under users. therefore you have to pass both to the form_for - a user and an item.
Something like this will probably work:
<%= form_for(current_user, #item) do |f| %>

Rails Error: ActiveRecord::RecordNotFound

I am working on my first Rails project and I am running into a persistent issue. I suspect it has something to do with the routing, however, I can't seem to find anything about it online.
I assume it a rather simple fix, so please take a look and let me know if you can help.
TL;DR
What I was trying to achieve
Account detail Cards display Name, Phone number, and a note.
A delete and edit button would allow users to delete or edit.
What is happening:
Edit and Delete buttons return a weird param.
see image
Image of error, Showing Rails getting a different ID
Controller
class AccountdetailsController < ApplicationController
def index
#accountdetail = Accountdetail.all
end
#I can't find the ID to show the relevent card.
def show
#accountdetail = Accountdetail.find(params[:id])
if #accountdetail.nil?
redirect_to accountdetail_path
end
end
def new
#accountdetail = Accountdetail.new
end
def edit
#accountdetail = Accountdetail.find(params[:id])
end
def create
#accountdetail = Accountdetail.new(accountdetail_params)
if #accountdetail.save
redirect_to #accountdetail
else
render 'new'
end
end
#it affects this
def update
#accountdetail = Accountdetail.find(params[:id])
if #accountdetail.update(accountdetail_params)
redirect_to accountdetail
else
render 'edit'
end
end
#and this
def destroy
#accountdetail = Accountdetail.find(params[:id])
#accountdetail.destroy
redirect_to accountdetail_path
end
private def accountdetail_params
params.require(:accountdetail).permit(:first_name, :last_name, :phone, :notes, :id)
end
end
Index.HTML.ERB
<div class="ui card">
<div class="content">
<a class="header"><%= account.first_name %> <%= account.last_name %> </a>
<div class="meta">
<span class="date"><%= account.phone %></span>
<strong><p><%= account.notes %></p></strong> <br>
<%= link_to "edit", edit_accountdetail_path(#accountdetail) %>
<%= link_to 'Inspect', accountdetail_path(#accountdetail) %>
</div>
</div>
</div>
<% end %>
Routes
Rails.application.routes.draw do
get 'welcome/index'
resources :articles do
resources :comments
end
resources :accountdetails
root 'welcome#index'
end
In you index.html.erb replace following
<%= link_to "edit", edit_accountdetail_path(#accountdetail) %>
<%= link_to 'Inspect', accountdetail_path(#accountdetail) %>
with
<%= link_to "edit", edit_accountdetail_path(account) %>
<%= link_to 'Inspect', accountdetail_path(account) %>
#accountdetail was providing you all the records of account, as it was firing select query in controller. But here we need only one instance, so account.
Hope this helps.

Setting user_id for post creation in Rails

I am having trouble setting the user_id on the creation of a post
def create
#post = Post.new(post_params)
#post.user_id = session[:id]
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
The error I get is specifically undefined method 'username' for nil:NilClass when redirected to the show action. A look at the database shows that no user_id is set.
I also tried passing the user_id as a hidden field. but this did not work either (a look at the logs showed the hidden field wasn't even being passed for some reason).
Would appreciate a point in the right direction,
Thank you !
EDIT: as requested here is the show controller
def show
#post = Post.find(params[:id])
#original_id = params[:original_id]
#comment = Comment.new
end
<%= form_for [:admin, #post] do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Below is the form
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.label :category %><br>
<%= f.text_field :category %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Routes:
root 'posts#index'
resources :posts do
resources :comments, shallow: true
end
resources :users, only: [:create]
#Posts
get "/meta", to: "posts#meta"
#User Routes
get "/signup", to: "users#new"
get "/success", to: "users#index"
#login Routes
get "/login", to: "sessions#login"
post "/sessions/login_attempt", to: "sessions#login_attempt"
#session routes
get "/sessions/home", to: "sessions#home"
get "/sessions/logout", to: "sessions#logout"
#admin routes
#resources :posts, module: 'admin', except: [:show, :index]
namespace :admin do
root 'posts#new'
resources :posts, except: [:show, :index]
end
Inside of your create method add
#post = Post.build(params[:post])
#post.user_id = current_user.id
This will grab the current user id for the given post.
If you have a has_many relationship between posts and users, why not do something like this:
#user = User.find(params[:id])
#post = #user.posts.new(params[:post])
The params might be different but this is the 'more ruby' way do do things. It explicitly notes the relationships between the two models. The above code should be in the #new action and then you would save it within the create action.
I feel like an idiot now but the issue was I was using session[:id] as opposed to session[:user_id]
Set in my sessions controller
def login_attempt
authorized_user = RegisteredUser.authenticate(params[:username_or_email],params[:login_password])
if authorized_user
session[:user_id] = authorized_user.id
flash[:notice] = "Wow Welcome again, you logged in as #{authorized_user.username}"
redirect_to(:action => 'index', :controller => "users")
else
flash[:notice] = "Invalid Username or Password"
flash[:color]= "invalid"
render "login"
end
end

Resources