I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand
Related
I have created a database of ideas with a votes field. I want users to be able to press a button to increase the vote count of an idea and then refresh the screen. I have created a method called increment_vote, but cannot seem to find how to save the new vote value in my database. This is my part of my index.html.erb code:
<% #ideas.each do |idea| %>
<tr>
<td><%= idea.content %></td>
<td><%= increment_vote(idea) %></td>
<td><%= link_to 'Vote', ideas_path(:mode => "Vote"), :class => "button", :method => :get %></td>
</tr>
If I call the increment vote method from the link to vote code, I get an "undefined method `to_model' for true:TrueClass. Did you mean to_yaml" error.
This is my method code in the ideas.controller:
helper_method :increment_vote
def increment_vote(idea)
idea.votes +=1
idea.save
end
This is currently causing the error, but it is increasing the vote of the first idea in the table.
Can anyone please help?
You can't call increment_vote method from view, you need to create controller action for it and call it when the user clicks the link
# views/ideas/index.html.erb
<% #ideas.each do |idea| %>
<tr>
<td><%= idea.content %></td>
<td><%= link_to 'Vote', upvote_idea_path(idea), class: "button", method: :post %></td>
</tr>
<% end %>
# routes.rb
resources :ideas do
post :upvote, on: :member
end
# ideas_controller.rb
def upvote
Idea.find(params[:id]).upvote
redirect_to :index
end
# models/idea.rb
def upvote
update(votes: votes + 1)
end
Hi I want to put a link in a index table of a resource to create a child resource.
I got a Sale, and an operation:
class Sale < ApplicationRecord
belongs_to :user
has_one :operation, dependent: :destroy
end
class Operation < ApplicationRecord
belongs_to :sale
end
And I want to be able to create an operation through an index table of sales.
Thing is, I need it to be created on the button/link click, and not be transferred to a new operation view. (Operation has only sale_id and id as attributes)
Something like that
<table>
<tr>
<th>Sale Id</th>
</tr>
<% #sales.each do |sale| %>
<td><%= sale.id %></td>
<td><%= link_to 'Show', sale_path(sale) %></td>
<td><%= link_to 'Edit', edit_sale_path(sale) %></td>
<td><%= link_to 'Delete', sale,
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td> <%= form_for (#operation) do |o| %>
<%= o.submit 'Create Operation'%>
<% end %>
</td>
</tr>
<% end %>
</table>
But I got this error: 'First argument in form cannot contain nil or be empty'
I also tried this:
<td>
<%= fields_for :operation, #sales.operation do |o| %>
<%= o.submit "Create Operation" %>
<% end %>
</td>
And I got this:
undefined method `operation' for Sale::ActiveRecord_Relation:0xb1a4ece4>
tried this as well :
<td>
<%= link_to 'Create Operation', 'operations#create' %>
</td>
But it sends me to the operation index view without creating an operation.
First argument in form cannot contain nil or be empty
The error means #operation is nil in the form. You should define #operation in the sales#index method as the form is in sales/index.html.erb
def index
#operation = Operation.new
end
I need it to be created on the button/link click, and not be
transferred to a new operation view
If you meant,you shouldn't be redirected to another view after the button, then you have to use AJAX. I recommend you see these Guides to understand how to do with AJAX
I have been practicing working on this rails application where I want to allow registered users to put up profiles of their dogs. But I just can't get the My Dogs page to display dogs that belong only to the current logged in user.
I already have the dog and user models linked via Active Record (User has_many :dogs, Dog belongs_to :user) but I don't know what to type in my dogmenu view to display only dogs that belong to the current logged in user. This is what I have so far:
views\access\dogmenu.html.erb <-- Notice that the page that will display the dogs for the current logged in user is located in the view of another controller.
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% Dog.all.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
Thank you.
You will need two things to make this work:
A User object for the logged in user
Filter the dog list based on that id
1. Current User
This is pretty straightforward, you should be able to find this with a little googling. The big question is whether you've implemented your own user management, or you're using something like Devise to manage that.
If it's Devise, take a look at Rails Devise: get object of the currently logged in user?
If you wrote your own, you could take a look at how Devise or other user management gems provide access to the current user object. I'll leave that up to you because it seems beyond the scope of your question
2. Filter the dog list
This is pretty simple, you've got a few options:
From the view
current_user.dogs.each do |d|
Dog.where(user: current_user).each do |d|
Dog.where(user_id: current_user.id).each do |d|
From the controller
What #Sean Huber suggested is cleaner - use any of my methods above, but from the controller. E.g.
#dogs = current_user.dogs
In short, only take the dogs that have the user id matching the current user's.
I would suggest you set an instance variable in your controller action for the current user's dogs. Something like this:
def dogmenu
# this assumes you have a current_user already defined
#dogs = current_user.dogs
end
Then switch your view to use the instance variable #dogs:
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% #dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
You need to retrieve the dogs related to the current user. Since these are the user's dogs, the logic should reside in the UsersController:
In _controller/users_controller.rb_
def your_method_name
#user = User.find(current_user.id)
#dogs = #user.dogs
render :dogmenu
end
Then in views/users/dogmenu.html.erb
<div id="dogdisplay">
<table>
<tr>
<th>Dog Name</th>
<th>Breed</th>
</tr>
<% #dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
</table>
</div>
These are user dogs so the view really belongs in the users folder.
To get current user dogs, you can use object current_user
Change this
Controller
def dogmenu
#dogs = current_user.dogs
end
View
<% #dogs.each do |d| %>
To make current_user can execute in view put a helper method.
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
#current_user ||= User.find_by_id(session[:user])
end
end
Finally you can use current_user in your view or helper
<% current_user.dogs.each do |d| %>
<tr>
<td><%= link_to d.dname, d %></td>
<td><%= d.breed %></td>
<td><%= link_to "Edit", edit_dog_path(d) %></td>
<td><%= link_to "Delete", d, method: :delete %></td>
</tr>
<% end %>
It's good for trying the first one where you're using instance variable. Hopefully it can help.
How can I return data from the database on another page?
I can file this under: views / posts / index.htm.erb
<h1>Listing posts</h1>
<table>
<tr>
<th>Titulo</th>
<th>Conteudo</th>
<th>Categoria</th>
<th>Criado em</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #posts.each do |post| %>
<tr>
<td><%= post.titulo %></td>
<td><%= post.conteudo %></td>
<td><%= post.category.name %></td>
<td><%= post.created_at.strftime("%d/%m/%Y") %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Delete', post, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Post', new_post_path %>
And I wanted to display these values on another page: views / home / blog.html.erb
How do I do this? Could you explain all the steps so that I can display these values in my other page.
Thanks Kocur4d
but how do I get only some information? eg: I would like that to appear in the title of the post page like this way (in blog.html.erb):
<div class="post-title">
<h2 class="title"> <a href="link_to_post"> **<% = post.titulo%>** </ a> </ h2>
</ div>
Step 1. Create controller
In your app root directory run:
rails g controller home blog
Modify controllers/homes_controller.rb :
class HomesController < ApplicationController
def blog
#posts = Post.all
end
end
Your controllers/posts_controller.rb should be already set up. Minimum what you need for your question is to have index method defined you might have other methods as well:
class PostsController < ApplicationController
def index
#posts = Post.all
end
end
Step 2. Extract Partial
change views/posts/index.htm.erb :
<h1>Listing posts</h1>
<%= render partial: 'shared/posts', object: #posts %>
<%= link_to 'New Post', new_post_path %>
create/modify views/home/blog.html.erb :
<h1>Listing posts</h1>
<%= render partial: 'shared/posts', object: #posts %>
<%= link_to 'New Post', new_post_path %>
create views/shared/_posts.html.erb :
<table>
<tr>
<th>Titulo</th>
<th>Conteudo</th>
<th>Categoria</th>
<th>Criado em</th>
<th></th>
<th></th>
<th></th>
</tr>
<% posts.each do |post| %>
<tr>
<td><%= post.titulo %></td>
<td><%= post.conteudo %></td>
<td><%= post.category.name %></td>
<td><%= post.created_at.strftime("%d/%m/%Y") %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Delete', post, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
Step 3. Set up routes.
You should have something like this in your routes.rb file:
resources :posts or match 'posts/index' => 'posts#index'
add this to config/routes.rb:
match 'home/blog' => 'home#blog'
so it might look like this(there is few variants):
config/routes.rb:
YourAppName::Application.routes.draw do
root to: 'posts#index'
resources :posts
match 'home/blog' => 'home#blog'
end
Now when you start rails server(assuming standard configuration) and visit:
127.0.0.1:3000/posts/index and 127.0.0.1:3000/home/blog
you should see same content.
This should work copy-and-paste but I could make some typos and other small mistakes(hope not, if ill find any ill try to edit them asap). In general look at it as you need 3 steps to forward http request down your rails application stack.
Map url to controllers using routes.
Create controllers and inside prepare data for views.
Display data in Views.
Look around in Rails Guides, Rails for Zombies and Rails Tutorial for more info.
---------Upadate to your second question-----------
I don't really understand what would you like to achieve?? At the moment both index.html.erb and blog.html.erb showing the same data, that was what you ware asking for?
post representing one post and is available in sharde/_posts.html.erb. You can't reference it from index.html.erb or blog.html.erb.
#posts represents all the posts and its available in index.html.erb or blog.html.erb.
render partial: 'shared/posts', object: #posts -- this line say "Hey man! Paste here content of shared/posts file, and btw I have here a local variable #posts so if you need to use that date in shared/posts file Ill name it posts from in side there"
To make them look different modify both files and part that will be identical for both of them is in a sharde/_posts.html.erb.
Try for example remove this line:
<td><%= post.category.name %></td>
from shared file to see what is going to happen.
Add some html tags and thinker with it.
Rails has may helper methods available' to find out about them check the links I give you and google, google, google.
Try to add some links with link_to helper
In your home controller, for the blog method, set #posts as you need...
Maybe
#posts = Post.all
I've been trying to figure out how to pass a variable between two views and I've looked at all the examples on stack overflow and I can't seem to make it work.
I have this in my users -> index.html.erb
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= user.id %></td>
<td><%= link_to 'Profile', user %></td>
<td><%= link_to 'Connect', new_relationship_path, :id => user.id %><td>
</tr>
<% end %>
I'm trying to pass user.id to my relationships -> new.html.erb view.
in my controller I have:
class RelationshipsController < ApplicationController
def new
#id = params[:id]
end
end
and finially I have relationships -> new.html.erb
<section id="main">
<h1>Sign Up</h1>
<td><%= #id %></td>
</section>
I believe :id isn't being passed correctly. What am I missing from all the other examples? I get no errors, just nothing is displayed.
This
link_to 'Connect', new_relationship_path, :id => user.id
is passing the :id as an html_option to link_to, so it will be used as an "id" attribute on your link element. What you want instead is to pass it as a parameter to the route helper:
link_to 'Connect', new_relationship_path(:id => user.id)
If users have one or many relationships, it could be smarter to user nested routes.
then you will be able to create relationship for a specific user through a direct url.
eg : new_user_relationship_path(user) # => /user/2134/relationship/new
then in your relationship controller a params[:user_id] would evaluate to 2134
you should look at : http://guides.rubyonrails.org/routing.html