Just now I am starting to study Ruby on Rails.
ruby version=1.8.7
rails version =2.3.2
I created delete and create new user action but present some errors,
the errors are:
uninitialized constant User::Id
Extracted source (around line #19):
16: <td><%= user.fname %></td>
17: <td><%= user.lname %></td>
18: <td><%= user.dob %></td>
19: <td><%= button_to "delete", :url => {:controller => :users,:action => 'destroy',:id =>user.id}, :method => :delete %></td>
20: </tr>
21: <% end %>
22: </table>
My MySQL database table is:
id fname lname dob
1 kamal vimal 2012.02.12
2 rahu sharmi 2012.05.26
3 mithun kavi 2012.03.07
Class user:
class User < ActiveRecord::Base
set_primary_key :id
has_one :id
end
My controller is:
class UsersController < ApplicationController
def index
#users=User.all
end
def destroy
# User.primary_key='id'
#users=User.find(:id)
#users.destroy
flash[:notice] = "You have successfully Delete Recode"
end
def new
#users=User.new
end
def create
#users=User.new(params[:users])
if #user.save
redirect_to_users_path
flash[:notice] = "Your record is created!"
else
render :action => "index"
end
end
end
My view is:
<% #users.each do |user| %>
<%= button_to "delete", :url => {:controller => :users,:action => 'destroy',:id =>user.id}, :method => :delete %>
<% end %>
Anyone can help me?
I see a couple of misunderstanding.
Users Controller
If you look the delete method in the controller
def destroy
#users=User.find(:id)
[...]
You are passing a symbol to the find function instead of the id from the delete request. You can get the id by using params[:id], as you have done with the create function.
def destroy
#users=User.find(params[:id])
[...]
The following are only suggestions.
I will also change the instance variable name from #users to #user here and in the new and the create method, since you are getting/build a single user.
If your routes.rb is set like
ActionController::Routing::Routes.draw do |map|
map.resources :users
end
you don't need to specify the url specifying the controller and the action in the button_to helper, but you can use the path helpers
button_to "delete", user_path(user), :method => :delete
User model
You can remove both the statements.
You should user set_primary_key only if the primary key in the table differs from the default 'id'.
The association is misused.
With the has_one method you are telling Rails the User model is related with the model 'id' through a 1:1 relation which, I suppose, is not what you want.
Final Thoughts
Read carefully the Ruby on Rails guide if you did not, it's a good starting point.
In addition, you are using a really old version of Rails and Ruby, which are not supported anymore. If there aren't any specific reason, like working on a legacy project, I suggest you to study a more recent version like Rails 4 on ruby 2.2.
Related
I am using a link from an index page that has a group of nested records (row) that I need to update all at once. The link goes to an edit action that I need to make update the attributes of nested records (prisms).
I tried using the simple_form gem methods for nested models. It gives me a field for all of the objects, when I only want one field to enter a value to them all. The builder from that looks usable, but I don't know how to use it to update the fields. Either way, the form isn't right.
I have tried every variation of form_for and fields_for I could find on Google to develop the edit form. It looks like I'm the only one on Earth trying to solve this problem.
This is how I have my routes set up:
resources :gardens, shallow: true do
resources :prisms
resources :rows
Here is how my garden model is now:
class Garden < ApplicationRecord
mount_uploader :picture, ImageUploader
belongs_to :user
has_one :photo
has_many :rows, :dependent => :destroy
has_many :prisms
geocoded_by :address
after_validation :geocode
after_commit :populate_garden!
def id
self[:id]
end
def populate_garden!
# row 0
(0..length-1).each do |i|
Row.create(row_num: i, garden_id: id)
end
end
end
The garden model creates my rows through the populate_garden! method.
Here is the row model:
class Row < ApplicationRecord
belongs_to :garden
has_many :prisms, :dependent => :destroy
accepts_nested_attributes_for :prisms
after_commit :populate_rows
def id
self[:id]
end
def populate_rows
# row 0
(0..garden.width-1).each do |i|
Prism.create(:row_id => self.id, :row_num => self.row_num, :col_num => i, :garden_id => self.garden_id)
end
end
end
The row model creates prisms in the populate_rows method.
Here is the prism model:
class Prism < ApplicationRecord
belongs_to :row
belongs_to :garden
include RankedModel
ranks :column_order
end
Here is the table from my index.html.erb that I click to open the edit action.
<table>
<% #rows.each_with_index do |gardenrow, index| %>
<% #rows.select { | row | row.row_num == index}.each do |row| %>
<td class="prism-cols">
<%= link_to 'Edit Row', edit_row_path(row), class:"dark-link" %>
<br /><i class="fas fa-arrow-down"></i>
</td>
<% end %>
<% end %>
</table>
The row passes nicely into the edit action, and I currently have this incorrect form:
<h1>The row brought into this form page is: </h1>
<%= #row.inspect %>
<div class="container">
<%= simple_form_for #row do |m| %>
<%= m.simple_fields_for :prisms do |p| %>
<%= p.input :crop_name %>
<% end %>
<%= m.button :submit %>
<% end %>
</div>
The rows_controller update method looks like this:
def update
#row = Row.find(params[:row_id])
#row.prisms.build
redirect_to root_path
end
I need one form field for crop_name that will change all of the prisms in the selected row with a single submit. I don't have any problems updating one prism at a time through an edit action on the prism. The difficulty I'm having is working through the nesting of prisms inside of a specific row.
With the help of my mentor below I was able to develop a form that works with the controller to make this work. Here is the updated code for later use with this type of problem.
Here is the form data:
<%= form_tag({controller: "rows", action: "update"}, method: "patch") %>
<%= label_tag(:crop_name, "Crop Name") %>
<%= text_field_tag(:crop_name) %>
<%= hidden_field_tag(:row_id, #row.id) %>
<%= submit_tag("submit") %>
Here is the controller update method:
def update
#row = Row.find(params[:id])
#garden = Garden.find_by_id(:garden_id)
#row.prisms.each do |p|
p.crop_name = params[:crop_name]
p.save!
end
redirect_to :controller => 'gardens', :action => 'show', id: #row.garden_id
end
Thanks for the help. I don't think I could have figured this out from the documentation alone.
If I'm understanding correctly, I think simple_form may be limiting you. A basic ruby form may do what you want. I'm not 100% sure what the best way is to do a simple_form on nested fields but this stackoverflow answer may be able to help more.
Using a basic ruby form
You want a form that has one field. When submitted, it will take the value from the submitted form and update that field for all prisms of that row. I would recommend digging more into the basics of ruby forms for this kind of scenario and then do something like this.
// html.erb
<%= form_tag({controller: "rows", action: "update_prism_crop_name"}, method: "post", class: "nifty_form") %>
<%= label_tag(:crop_name, "Crop name") %>
<%= text_field_tag(:crop_name) %>
<%= hidden_field_tag(:row_id, #row.id) %>
<%= submit_tag("Submit") %>
<% end %>
// rows_controller
def update_prism_crop_name
#row = Row.find(params[:row_id])
#row.prisms.each do |prism|
prism.crop_name = params[:crop_name]
prism.save!
end
# other redirect stuff
end
The form_tag explicitly calls out an action but I have to imagine that you'll need to build a route for this custom action as well.
I haven't tested any of this and I'm a bit rusty in rails but I believe something like this would work.
What's the best (simplest) way to walk through MVC and check if everything is set up right?
I get a bit frazzled and I feel like there must be a really simple fix to error messages like these:
undefined method `invitations_path' for #<#<Class:0x00000105ad5cb8>:0x00000105820b30>
After adding small amounts of code to my app things break and I want to trouble shoot them myself.
Thanks for the tips!
EDIT
Perhaps troubleshooting the specific issue will lead way to a generalized approach,
Link_to is not linking Used <%= %> instead of <% %>.
The above error is generated when visting localhost:3000/invitation/new
view (in home/index.erb.html)
<% if #user.invitation_limit > 0 %>
<% link_to 'Send Invitations', new_invitation_path %>
(<%= #user.invitation_limit %> left)
<% end %>
view (in invitation/new.erb.html)
<%= error_messages_for :invitation %>
<% form_for #invitation do |f| %>
<p>
<%= f.label :recipient_email, "Friend's email address" %><br />
<%= f.text_field :recipient_email %>
</p>
<p><%= f.submit "Invite!" %></p>
<% end %>
controller
class InvitationController < ApplicationController
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user
if #invitation.save
if logged_in?
Mailer.deliver_invitation(#invitation, signup_url(#invitation.token))
flash[:notice] = "Thank you, invitation sent."
redirect_to projects_url
else
flash[:notice] = "Thank you, we will notify when we are ready."
redirect_to root_url
end
else
render :action => 'new'
end
end
end
model
class Invitation < ActiveRecord::Base
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
attr_accessible :recipient_email, :sender_id, :sent_at, :token
end
routes.rb
resources :home, :only => :index
resources :invitation
You can create request specs for each of your controller actions. Request specs follow the request all the way from the controller to rendering the view, and if there is an error it will show up in the request spec.
This may take time to set up, but will save you lots of time in the future, as you don't have to manually test every page when you want to roll out a new version of your website.
I have a basic app and I'm trying to destroy a record in a table called meeting_participants based on both the meeting_id and participant_id (which are columns in meeting_participants).
I have changed the destroy action in my meeting_participants_controller, to accept the meeting_id and participant_id and then delete the appropriate record.
def destroy
session[:return_to] = request.referer
#meeting_participant = MeetingParticipant.find_by_meeting_id_and_participant_id(params[:meeting_id], params[:participant_id])
#meeting_participant.destroy
redirect_to session[:return_to]
end
I have a button in a view I would like to use to call the meeting_participants#destroy controller, using the following code.
<table>
<% #participants.each do |participant| %>
<tr>
<td><%= participant.name %></dt>
<td>
<% participant.meetings.each do |meeting| %>
<%= meeting.name %>
<%= button_to( "Remove Meeting",
{:controller => "meeting_participants",
:action => "destroy",
:meeting_id => meeting.id,
:participant_id => participant.id },
:method => :delete,
:confirm => "Are you sure?") %>
<br/>
<% end %>
</td>
</tr>
<% end %>
</table>
I think that I am successfully sending the correct participant_id and meeting_id parameters to the controller but I am getting a "No route matches" error because my route for meeting_participants#destroy is expecting a single :id parameter instead. rake routes gives...
meeting_participant DELETE /meeting_participants/:id(.:format) meeting_participants#destroy
Does anyone know of a way to change my route to expect the two new parameters instead of id? Or maybe there is a better approach altogether. I find routes very confusing.
Thanks.
My routes.rb files is...
MyApp::Application.routes.draw do
resources :meeting_participants
resources :participants
resources :meetings
end
I'd probably create a route to handle that request. Maybe something like:
match '/delete_meeting_participants/meeting/:meeting_id/participant/:participant_id' => 'meeting_participants#delete_meeting_participants', :as => 'delete_meeting_participants'
Then, in your controller you would have an action called delete_meeting_participants that has the same logic currently in your destroy action. Obviously you would have to update your button_to with the name of the newly created action.
im using Rails 3.2.8 and SQLite 1.3.6
and im running into troubles changing boolian variables in the database
SQLite translates "t" and "f" as true and false
this function wont update the :approved attribute (that is default false)
def activate
#user = User.find(params[:id])
if #user.update_attribute(:approved, 't')
redirect_to "/" #this is the return i get so the update returns true
else
render "/users?approved=false"
end
end
But changing strings like #user.update_attribute(:email,'root#email.org') will update the email
how can i fix this do i need some kind of an sqlite adapter ?
i already installed activerecord-jdbcsqlite3-adapter and it messed up my app because i was too hasty and didnt notice that it was deprecated :P
i found this thread : Rails 3 SQLite3 Boolean false
but i dont understand what i need to do in order to make Rails and SQLite communicate correctly as im a newbie in rails :)
also i think its worth mentioning that im running this on windows 7 x64
UPDATE
Apparently Rails does indeed know how to communicate with Sqlite, but the i have no idea why my code dosnt work for boolians lol
in my view i have :
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= user.email %></td>
<td><%= user.approved? %></td>
<td>
<% if !user.approved? %>
<%= link_to 'Approve', active_user_path(user), :method => :put %>
<% end %> </td>
</tr>
<% end %>
This lists all the unapproved users and a link to activate them (set the bool to true)
and in my controller i have
def activate
#user = User.find(params[:id])
if #user.update_attribute(:approved, true)
redirect_to "/" #this is the return i get so the update returns true
else
render "/users?approved=false" #this is not rendered
end
end
and my route
match "users/:id/activate" => "users#activate", :as => "active_user"
This works for other strings like the user name, address etc but not the bool's
If the approved column on #user is a boolean, you should just pass true/false and let the database adaptor figure it out.
#user.update_attribute(:approved, true)
I solved this by using a integer migration to my users table, i have no idea as of why #user.update_attribute(:approved, true) didnt save to the database it must have had something to do with my setup
i made the migration add_column :users, :is_approved, :integer, :default => 0 and when i want to activate a user i simply flip the integer value to 1
I have the following singular route:
scope '/seller' do
resource :seller_profile, :path => "/profile", :only => [:show, :edit, :update]
end
and the following controller:
class SellerProfilesController < ApplicationController
before_filter :validate_user_as_seller
def show
#seller_profile = current_user.seller_profile
end
def edit
#seller_profile = current_user.seller_profile
end
def update
#seller_profile = current_user.seller_profile
if #seller_profile.update_attributes(params[:seller_profile])
redirect_to(seller_profile_path, :notice => 'Profile was successfully updated.')
else
render :action => "edit"
end
end
end
I use a singular route given that the user must be authenticated before gaining access to the controller and therefore I can get the seller_profile from the user logged in.
This works like a charm, with only one problem. When I edit the seller_profile and validation error happen, the form is edited again and the errors are displayed correctly. The problem is that rails appends to the url the id of the edited record. For instance,
when I first edit the record, the url is:
http://0.0.0.0:3000/seller/profile/edit
but if the form is submitted with validation errors, the form itself is redisplayed under
http://0.0.0.0:3000/seller/profile.2
where 2 is the ID of the record being edited.
The form is the following:
<%= simple_form_for #seller_profile do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.submit %>
<% end %>
Everything, as said, works great but I would totally mask the ID in the url. What should I do?
I have not really worked too much with simple_form_for. But it looks like it is guessing your url always as if they were not single resources. You can provide a custom one:
<%= simple_form_for #seller_profile, :url => seller_profile_path do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.submit %>
<% end %>