I'm trying to achieve a simple 1 to 1 relation in Rails 3 where a user can connect a bank account.
class User < ActiveRecord::Base
has_one :bank
accepts_nested_attributes_for :bank
attr_accessible :bank_attributes
end
class Bank < ActiveRecord::Base
belongs_to :user
end
Route
resources :users do
resources :bank
Now when i build a new bank object for a user in users/1/bank/new like this:
def new
#user = User.find(current_user.id)
#bank = #user.build_bank
end
I get an error on my for which looks like this:
<%= simple_form_for(#bank) do |f| %>
The error is:
undefined method `banks_path' for #<#<Class:0x007fa7bd090f08>:0x007fa7c0545b40>
My goal is to have a separate form for a user to add there bank account information.. Hope someone can help me in the right direction to do this. I also use ActiveAdmin and the relation with forms etc works fine there.
Any help is appreciated!
Since bank is nested under user, you need to give the user to the form:
<%= simple_form_for([#user, #bank]) do |f| %>
In addition, your routes file should be
resources :users do
resource :bank
This will give you a user_bank_path for a user
You need to declare resource in plural form regardless of the association type.
So, your resource declaration
resources :users do
resource :banks
end
Related
I'm having trouble creating the correct form_with syntax to create a record for a has_many through association and cannot find an example to copy.
My model has a Factory. Factories can have Equipment. Equipment can have many EquipmentVariations. Variations are specific to a particular type of equipment, but are different for each specific piece of equipment (so the VariationType is associated with the EquipmentType)
I can create the factory (e.g. localhost/factories/1)
I can create the equipment at the factory (e.g. localhost/factories/1/equipment/1)
But I cannot manage to make a form that creates EquipmentVariations. That is, when I navigate to localhost/factories/1/equipment/1 I want a form to add EquipmentVariations to that Equipment entry.
Here's my code:
routes.rb
resources :factories do
resources :equipment do
resources :equipment_variations
end
end
resources :equipment_types do
resources :variation_types
end
Models
class Factory < ApplicationRecord
has_many :equipment
end
class Equipment < ApplicationRecord
belongs_to :factory
belongs_to :equipment_type
has_many :equipment_variations
has_many :variation_types, through: :equipment_variations
end
class EquipmentVariation < ApplicationRecord
belongs_to :equipment
belongs_to :variation_type
end
class VariationType < ApplicationRecord
belongs_to :equipment_type
has_many :equipment_variations
has_many :equipment, through: :equipment_variations
end
And the view in app/views/equipment/show.html.erb
<h1><%= #equipment.equipment_type.name %></h1>
<h3>Add Variation</h3>
<%= form_with(model: [#equipment, VariationType.new], url: factory_equipment_equipment_variations_path, local: true) do |form| %>
<%= form.submit %>
<% end %>
This is as close as I have been able to manage, but gives the error: No route matches {:action=>"index", :controller=>"equipment_variations", :factory_id=>"2", :id=>"3"}, missing required keys: [:equipment_id]
Basically, I need to be able to post to the URL /factories/1/equipment/1/equipment_variations from the page at /factories/1/equipment/1. The route given for that is factory_equipment_equipment_variations which is why I specified that in the url parameter, but I feel there must be a simpler way to acheive this. What should the form_with parameters look like?
Ok, so I figured this out. I was close, but the correct syntax is as follows
<%= form_with(model: [#factory, #equipment, EquipmentVariation.new], local: true) do |form| %>
So you need to give the model: parameter all the models for the route (factory, equipment) and it will figure out the correct path by itself and submit the parameters appropriately.
Also, my controller for EquipmentVariation called by above looks like:
def create
#equipment = Equipment.find(params[:equipment_id])
#equipment.variation_types << VariationType.find(params[:variation_type][:variation_type_id])
end
Hope this helps someone in future!
So I am making a chat app, and I want users to be able to leave chat rooms. This would be done by posting a delete request to a route like /users/:id/chat_rooms/leave/:chat_room_id.
The Users model has has_many :chat_rooms, through: chat_room_users while ChatRooms has has_many :users, through chat_room_users. The UsersController has a leave action, which I want to call using this request on this url.
I want to create a link to this url on a view that I have. I already have a variable #user for the current user and #chosen for the current chat room available on the view. So how would I do a link_to and route for this setup? I have delete /users/:id/chat_rooms/leave/:chat_room_id in the routes.rb file, but how would I do the link_to?
Thank you.
You're overcomplicating it.
DELETE /chat_rooms/:chat_room_id/leave
Instead of passing the user id via the URL you should instead get it through the session or a token (if its an API app).
Rule of thumb: resources should never be nested more than 1 level
deep. A collection may need to be scoped by its parent, but a specific
member can always be accessed directly by an id, and shouldn’t need
scoping (unless the id is not unique, for some reason).
http://weblog.jamisbuck.org/2007/2/5/nesting-resources
This is just a loose example of how to solve this:
# routes.rb
resources :chat_rooms do
member do
post :join
delete :leave
end
end
class User
has_many :chat_room_users
has_many :chat_rooms, though: :chats
end
class ChatRoomUser
belongs_to :user
belongs_to :chatroom
end
class ChatRoom
has_many :chat_room_users
has_many :users, though: :chats
end
Putting this in UsersController is pretty questionable. I would instead place it in ChatroomsController.
class ChatroomsController
# ...
# POST /chat_rooms/:chat_room_id/join
def join
#chat_room = ChatRoom.find(params[:id])
#chat = current_user.chat_room_users.new(chat_room: #chat_room)
if #chat_room.create
# ...
else
# ...
end
end
# DELETE /chat_rooms/:chat_room_id/leave
def leave
#chat_room = ChatRoom.find(params[:id])
#chat = current_user.chat_room_users.find_by(chat_room: #chat_room)
#chat.destroy
end
end
<%= button_to 'Join', join_chat_room_path(#chat_room), method: :post %>
<%= button_to 'Leave', leave_chat_room_path(#chat_room), method: :delete %>
In my Rails app, each User has many graphs, each Graph has many trackables, and each Trackable has many points (with a value and time). Users are able to add (or remove) different trackables to plot vs created_at time. Users can to go to a graph's show page and submit forms to create new points for each trackable the graph has.
In the GraphController show action, I assign all the trackables of the current graph to #trackables, and then in views/graphs/show I loop through each |trackable| and attempt to make a new point for the trackable.
===============
EDIT: This is the error raised in the browser when trying to access the graph show page
NoMethodError in Graphs#show
undefined method `trackable_points_path' for #<#:0x007fbce1548008>
and then this line is highlighted in the Extracted source in the browser
- simple_form_for([trackable, trackable.points.build]) do |f|
================
EDIT 2: Here is my routes as requested
Rails.application.routes.draw do
devise_for :users
resources :graphs do
resources :trackables do
resources :points
end
end
root 'graphs#index'
end
Models
class Graph < ActiveRecord::Base
belongs_to :user
has_many :trackables
end
class Trackable < ActiveRecord::Base
belongs_to :graph
has_many :points
end
class Point < ActiveRecord::Base
belongs_to :trackable
end
Graphs and (Updated) Points Controller
class GraphsController < ApplicationController
def show
#graph = Graph.find(params[:id])
#trackables = #graph.trackables.all
end
end
class PointsController < ApplicationController
def create
#trackable = Trackable.find(:trackable_id)
#point = #trackable.points.create(params.require(:point).permit(:value))
end
end
views/graphs/show.html.haml
- #trackables.each do |trackable|
- simple_form_for([trackable, trackable.points.build]) do |f|
= f.input :value, input_html: { class: "form-control" }
= f.button :submit, class: "btn btn-default"
I'm new to all this and my attempt doesn't seem to work. Any help or suggested reading would be greatly appreciated! Thanks
I think that the problem here is the fact that you are accessing the Trackable object directly in the form, but you have no actual path to address the Trackable without accessing the Graph first. Ie. you have a graph_trackables_path() and graph_trackable_points_path() methods, but no trackable_points_path() method.
Probably you should pass the #graph object to the simple_form_for call:
- simple_form_for([#graph, trackable, trackable.points.build]) do |f|
...
Otherwise you can define the Trackable objects as a separate resource in your routes.rb file, but this will probably modify the underlying logics in the controller.
resources :graphs do
resources :trackables do
resources :points
end
end
resources :trackables do
resources :points
end
I have a one-to-one models for user and profile.
The following is the code for the User model created by device.
class User < ActiveRecord::Base
has_one :profile , dependent: :destroy
end
Code for Profile model.
class Profile < ActiveRecord::Base
belongs_to :user
end
Now I have basic Profile for a User which was created at sign up. Now how do I go about editing user profile using the helper device provides current_user with form_for?
We did something like this:
#app/models/user.rb
Class Model < ActiveRecord::Base
before_create :build_profile
end
This populates the profile record in the database, allowing you to update it later on
Once you've saved the user, you will be best using accepts_nested_attributes_for to populate & save profile options through a form for the user, like this:
#config/routes.rb
resources :users do
resources :profiles
end
#app/views/profiles/edit.html.erb
<%= form_for #profile do |f| %>
<%= f.hidden_field :user_id, current_user.id %>
<%= f.text_field :your_profile_options %>
<% end %>
This is a very basic way to do it, but hopefully will give you more ideas. If you want to see this in the wild, check out http://video-conference-demo.herokuapp.com (it uses Devise to handle users & has extra "profile" model too)
I am using Ruby on Rails 3 and I am trying to submit namespaced Account using an ActiveRecord association.
In the router I have
resources :users
namespace "users" do
resources :accounts
end
In the User model I have:
class User < ActiveRecord::Base
has_one :account,
:class_name => "Users::Account"
end
In the User controller I have
class UsersController < ApplicationController
def new
#user = User.new
...
end
end
In order to submit the User Account, in the form view I tryed to do like the following:
<%= form_for([:users, #user.account]}) do |f| %>
...
<% end %>
but that doesn't work. So what I have to do to make it to work?
Some things look mixed up. You have view for users, but you are creating User::Account there?! In controller you didn't create that account. Perhaps:
#user = User.new :account => Users::Account.new
But pay attention that you either need to move your logic in Users::AccountController or if you want to create both User and it's account in the same view, than you use nested_forms for account and than you should post form to your #user model with accepting_nesting_attributes for account too.