I want to call a method that updates an attribute when saved.
Here is my index.html.erb
<% #users.each do |user| %>
<div>
<strong><%= user.email %></strong>
</div>
<% if can? :update, User %>
<%= link_to 'Make Author', User, method: :add_roles %>
<% end %>
Below is my user_controller.rb
def add_roles
respond_to do |format|
if #user.update(user_params)
user.author = true
user.save!
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
It doesn't update the attribute though. I think it is because I am not properly attaching it to the correct user. I want to current_user to update another user.
I think the solution is simple, first do what avlazarov said in his comment:
In the view <%= link_to 'Make Author', "/users/#{user.id}/add_roles",
method: :patch %> In the routes.rb patch '/users/:id/add_roles' =>
'user#add_roles'
Or something simpler, in routes.rb:
resources :users do
patch :add_roles, on: :member
end
then in view:
<%= link_to 'Make author', add_roles_users_path(user) %>
Then rename user_controller.rb placed in app/controllers to users_controller.rb and make sure the class name is UsersController.
Related
My rails project consists of three models: User, Groups and Transactions. Groups and Transactions are connected by a has_and_belongs_to_many relationship and both belong to User. I'm trying to implement a feature where you can add new transactions on a groups' show page that will automatically be associated with the show pages' group. I've tried the following but in the transactions controller rails doesn't get which group the transaction is supposed to be associated with.
Groups' show page:
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #group.name %>
<% #group.deals.each do |deal| %>
<%= deal.name %>
<%= deal.user.name %>
<%= link_to 'Show', deal %>
<% end %>
</p>
<%= link_to 'Edit', edit_group_path(#group) %> |
<%= link_to 'Back', groups_path %>
<%= link_to 'New Transaction', new_transaction_path(#group) %> |
Group's controller page:
# GET /transactions/new
def new
#transaction = Transaction.new
end
# POST /transactions or /transactions.json
def create
#transaction = Transaction.new(transaction_params.merge(user_id: current_user.id))
respond_to do |format|
if #transaction.save
format.html { redirect_to #transaction, notice: "Transaction was successfully created." }
format.json { render :show, status: :created, location: #transaction }
#transaction.groups << #group
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
If I replace #group with f.e. Group.first the association is created - it's the wrong one in most cases ofc tho. Does the solution lie within in the views maybe, can anyone help out?
I've been trying to build a facebook/blog type app where comments show directly under new posts, and you can also POST a new comment by rendering a form directly under the corresponding Post. As you'll learn in the rest of my post, I'm fairly new to Rails so any resources that directly help me understand the issue I'm having (even if it's just pointing me to the right parts of the Rails docs) would be super helpful.
As of right now, my homepage renders the post#index action, as well as a a post form so that you can create new posts directly on the index page. All of this works fine until I try to render my comment form. As a note, I'm only focusing on creating a new comment before implementing editing and deleting (not that that should affect anything I wouldn't think).
Unfortunately I keep getting this error -
Moreover, when I split each of these pages into a more traditional, link_to XXXX_path style where every form and action is on its own url page, everything works fine. I think there might be something fundamental that I'm just not understanding. So, before showing my code I'll just give a quick explanation of my understanding of how I expect things to work in my app
On the index.html.erb view:
Render the index page
Show each individual post and any corresponding info I want to display with my each method.
pass the specific instance of Post using <%= render 'comment_form', :post => post %>. This should also give me access to all of the params of said instance of post in my _comment_form.html.erb partial.
On the _comment_form.html.erb partial:
add model: [post, #comment] (as my comment controller is nested in post) so that Rails knows to build a new comment with the associated post instance that was pushed through my index view.
At the end of the day, if I had to guess, my issue is with my controllers - I feel like I've put the correct code in the methods/actions, but my hunch is that there's something conflicting between the #post instance variable and the post instance being iterated over in my each method. I'm really not sure what the problem is and any help would be much appreciated. I hope I didn't over (or under) explain my problem. Thanks for the help in advance!
views/posts/index.html.erb
<p id="notice"><%= notice %></p>
<nav>
</nav>
<h1>Posts</h1>
<table>
<thead>
<tr>
<th>User</th>
<th>Body</th>
<th colspan="3"></th>
</tr>
</thead>
<%= render 'form' %>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= link_to post.user.email, user_path(post.user_id) %></td>
<td><%= post.body %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<td>
</tr>
<tr>
<%= render 'comment_form', :post => post %>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_post_path %>
views/posts/_comment_form.html.erb
<% if user_signed_in? %>
<%= form_with(model: [post, #comment], url: post_comments_path, method: "post", local: true) do |form| %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
<% else %>
Please sign in to comment on the post!
<% end %>
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
#before_action :authenticate_user!
# GET /posts
# GET /posts.json
def index
#posts = Post.all.order("created_at DESC")
#post = post_exists?
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = current_user.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to index, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow a list of trusted parameters through.
def post_params
params.require(:post).permit(:body)
end
def post_exists?
current_user.posts.build if current_user != nil
end
end
comments_controller.rb
class CommentsController < ApplicationController
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.build
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comments_params)
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to posts_path, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def destroy
end
private
def comments_params
params.require(:comment).permit(:body)
end
end
routes.rb
devise_for :users, controllers: {
sessions: 'users/sessions'
}
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
end
resources :posts do
resources :comments, only: [:new, :create, :destroy]
end
resources :users
root to: 'posts#index'
Models
>user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
>post.rb
belongs_to :user
has_many :comments, dependent: :destroy
>comment.rb
belongs_to :user
belongs_to :post
The error is saying that it is missing the post_id on line 2 in your comment_form.
You got:
<%= form_with(model: [post, #comment], url: post_comments_path, method: "post", local: true) do |form| %>
The url is set to post_comments_path but it doesn't knows which post so you need to pass the post to it as an argument like so:
<%= form_with(model: [post, #comment], url: post_comments_path(post), method: "post", local: true) do |form| %>
Although this will probably solve the current error, you will hit another error since you also got #comment in the comment_form and in your posts#index you don't declare #comment. You also can't declare #comment because it is depending on the post. You could try to solve that with:
<%= form_with(model: [post, post.comments.new], url: post_comments_path, method: "post", local: true) do |form| %>
undefined method `each' for nil:NilClass:
<% #users.each do |user| %>
Admins in my app can create users manually through a user dashboard that I created. However, after clicking the button to create a new user, some strange things happen.
First, I am presented with "undefined method 'each' for nil:NilClass", with a reference to the Users Index View (which is where admins are redirected after user creation. If I refresh the page, the browsers URL box still states that it's on the Users Index page, however, the screen displays the New User page with statement saying that the entered User Email is already taken. If I manually go to the User Index page, then I can see the User added successfully, and I am NOT presented with the undefined method error. What the heck! I know I have some messy code, but I have no idea why this is happening.
Users Controller Excerpt:
def index
#users = User.all
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { render :index, notice: 'user was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
Users Index View Excerpt:
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.admin ? "<i style='color:green' class='glyphicon glyphicon-flash'><strong>Admin</strong></i>".html_safe : " " %></td>
<td><strong><%= link_to user.email,user %></strong></td>
<td><span class="badge"><%= user.sign_in_count %></span></td>
<td><%= user.activated ? "<i style='color:green' class='glyphicon glyphicon-ok'></i>".html_safe : "<i style='color:red' class='glyphicon glyphicon-remove'></i>".html_safe %></td>
<td><b>
<%= link_to user do %>
<span class="badge"><%= user.apps.count %></span> View
<% end %>
</b></td>
<td><%= link_to "<i class='glyphicon glyphicon-pencil'><strong> Manage</strong></i>".html_safe, edit_user_path(user), class: 'btn btn-primary btn-xs' %></td>
<td><%= link_to "<i class='glyphicon glyphicon-remove'></i> Destroy".html_safe, user, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-xs' %>
</td>
</tr>
<% end %>
</tbody>
Routes File Excerpt:
devise_for :users, :path_prefix => 'u'
resources :users
devise_scope :user do
get "login", to: "devise/sessions#new", as: :login
get 'logout', to: 'devise/sessions#destroy', as: :logout
get 'user/edit', to: 'devise/registrations#edit', as: :change_password
end
Let me know if you'd like any additional code. You can find the entire app on GitHub here:
https://github.com/nickdb93/QwesteraCONNECT/tree/completion
Your solution is perfect:
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'user was successfully created.' }
This works because you changed render to redirect_to. Render will render a view with the instance variables it has access to in that action. In your original problem, you called render in the #create action. This didn't work because the #create action doesn't have access to the #users instance variable.
redirect_to tells the browser to re-request a new url. In your working solution, you are telling the browser to request the url that goes to the #index action. The index action will then set the #users instance variable and render :index
These resources explain the difference between render and redirect_to better than I ever could:
Are redirect_to and render exchangeable?
Render and Redirect
I probably didn't solve this the best way, but I found a convenient workaround.
I changed the if #user.save action in my UsersController#create as follows.
respond_to do |format|
if #user.save
format.html { render :index, notice: 'user was successfully created.' }
was changed to:
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'user was successfully created.' }
Please add your input if you have a better way. I'd love to learn the Rails way to do this.
I am trying to learn Rails and am making my first app and am running into this error:
ActiveRecord::RecordNotFound in PartsController#show
Couldn't find Part with id=new_ic
with the highlighted source:
def set_part
#part = Part.find(params[:id])
end
I am brand new to rails and i can't figure out what is wrong and I can't find any help online either. The app is a part management system for electronic components. The form gets filled out and the data is saved to the database for future reference/updating. Could someone please help?
Source code time:
parts/_ic_form.html.erb
<h1>Add An IC</h1>
<%= simple_form_for #parts do |f| %>
<%= f.input :component_type, :as => :hidden, :input_html => { :value => "IC"} %>
<%= f.input :ic_model, label: 'IC Model' %>
<%= f.input :ic_manufacturer, label: 'IC Manufacturer' %>
<%= f.input :ic_pinCount, label: 'IC Pin-Count' %>
<%= f.input :ic_mountType, collection: ["Through Hole", "Surface Mount"], label: 'IC Mount Type' %>
<%= f.input :ic_package, label: 'IC Package' %>
<%= f.input :ic_quantityOnHand, label: 'Quantity On Hand' %>
<%= f.input :ic_quantityOnOrder, label: 'Quantity On Order' %>
<%= f.button :submit %>
<% end %>
parts/new_ic.html.erb
<%= render 'ic_form' %>
parts/new.html.erb
<h1>New part</h1>
<%= link_to 'IC', 'new_ic' %>
<%= link_to 'Back', parts_path %>
parts_controller.rb
class PartsController < ApplicationController
before_action :set_part, only: [:show, :edit, :update, :destroy]
before_filter :initialize_parts
def initialize_parts
#parts = Part.new
end
# GET /parts
# GET /parts.json
def index
#parts = Part.all
end
# GET /parts/1
# GET /parts/1.json
def show
end
# GET /parts/new
def new
#part = Part.new
end
# GET /parts/1/edit
def edit
end
# POST /parts
# POST /parts.json
def create
#part = Part.new(part_params)
respond_to do |format|
if #part.save
format.html { redirect_to #part, notice: 'Part was successfully created.' }
format.json { render action: 'show', status: :created, location: #part }
else
format.html { render action: 'new' }
format.json { render json: #part.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /parts/1
# PATCH/PUT /parts/1.json
def update
respond_to do |format|
if #part.update(part_params)
format.html { redirect_to #part, notice: 'Part was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #part.errors, status: :unprocessable_entity }
end
end
end
# DELETE /parts/1
# DELETE /parts/1.json
def destroy
#part.destroy
respond_to do |format|
format.html { redirect_to parts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_part
#part = Part.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def part_params
params[:part]
end
end
routes.rb Pretty sure i screwed this one up too
Pms::Application.routes.draw do
resources :parts
resources :parts
root to: "parts#new_ic"
end
rake routes Output:
Prefix Verb URI Pattern Controller#Action
parts GET /parts(.:format) parts#index
POST /parts(.:format) parts#create
new_part GET /parts/new(.:format) parts#new
edit_part GET /parts/:id/edit(.:format) parts#edit
part GET /parts/:id(.:format) parts#show
PATCH /parts/:id(.:format) parts#update
PUT /parts/:id(.:format) parts#update
DELETE /parts/:id(.:format) parts#destroy
GET /parts(.:format) parts#index
POST /parts(.:format) parts#create
GET /parts/new(.:format) parts#new
GET /parts/:id/edit(.:format) parts#edit
GET /parts/:id(.:format) parts#show
PATCH /parts/:id(.:format) parts#update
PUT /parts/:id(.:format) parts#update
DELETE /parts/:id(.:format) parts#destroy
root GET / parts#new_ic
One problem is in this line:
<%= link_to 'IC', 'new_ic' %>
link_to should look like this:
link_to "Profile", profile_path(#profile)
#Profile is the name
#profile_path(#profile) is the link
Try this instead:
#parts/new.html.erb
<%= link_to 'IC', root_path %>
in your routes, root GET / parts#new_ic is linking to your new_ic action. I'd disagree with the way you access it (via root) - but it will work if you want to access the new_ic action. Why is this your root route, though?
My update.html.erb:
<% #uploads.each do |upload| %>
<p><%= upload.name %></p>
<p class="grey">
<%= best_in_place upload, :place, type: :select, collection: [ ["Home", "Home"],["Sauna", "Sauna"]]%>
</p>
<%end%>
controller:
def show
#uploads = Upload.all
end
def update
#uploads = Upload.all
#upload = Upload.find(params[:id])
respond_to do |format|
if #upload.update_attributes(params[:upload])
format.html { redirect_to #upload, notice: 'Upload was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #upload.errors, status: :unprocessable_entity }
end
end
end
The problem is that I get the error: undefined methodeach' for nil:NilClass` , meaning that my controllers do not pass my object to the variable #uploads. Why do not the do that and how can I fix it? Thanks in advance.
ps. I could write at the top of my view something like this:
<% #uploads=Uploads.all%>
But that is not the best idea.
Thanks in advance
<% #uploads.each do |upload| %>
<%end if #uploads.present? %>
IF your routes are RESTful routes, the update method is a HTTP PUT method and it shouldn't have a template. What you are looking for is a edit action:
def edit
#uploads = Upload.all
end
#katja: Referring to your comment.
update is a HTTP PUT request, you cant get a record in that but edit is a get request you can get all records in edit action.
You can add a before_filter callback to your edit action.
before_filter :get_all_uploads, only: [:edit]
def get_all_uploads
#uploads = Upload.all
end
And in your edit.html.erb you can do
<% #uploads.each do |upload| %>
<p><%= upload.name %></p>
<p class="grey">
<%= best_in_place upload, :place, type: :select, collection: [ ["Home", "Home"],["Sauna", "Sauna"]]%>
</p>
<% end %>