I am new to rails and I am having a hard time assigning the foreign key user_id to user_profile.
When a user creates an account it is saved to the database, then they are taken to create a profile. The user can create the profile and the profile is saved to the database. I used to have
<tr>
<th><%= f.label(:user_id, "User ID") %></th>
<td><%= f.text_field(:user_id) %></td>
</tr>
assign
on the user profile form, and it worked, user.user_profile showed there was a relationship. but I don't want a user to have to/be able to choose the user_id they are creating a profile for. I can't figure out how to assign the user_id to the user_profile. in the controller for user_profiles I have
def new
#user = User.find(session[:user_id])
#user_profile = UserProfile.new({:user_id => #user.id})
end
and for the new page for user_profiles I have
<%= form_for(:user_profiles, :url => {:action => 'create', :user_id => #user.id}) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<% end %>
any ideas? Thank You
Assuming you are on rails 4, you just need to add into User.rb
has_many :user_profiles, dependent: :destroy
and into user_profile.rb
belongs_to :user
validates :user_id, presence: true
user_profiles_controller.rb
def create
#user_profile = current_user.user_profiles.build(user_profile_params)
....
end
private
def user_profile_params
params.require(:user_profile).permit(:param1, :param2)
end
form view
<%= form_for(#user_profile) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<% end %>
Related
I want to modify my application in a way that on the signup page, user specifies his company. If the company with a particular name already exists, the newly created user gets assigned to the company (by company_id), if not, the company gets created in the company table, and the user gets the company_id assigned in the users table record.
I've managed to make the app create the user, and create a correct company in another table, But I can't figure out how to make it so that if the company already exists, user just gets the existing company id.
Now on to what I've done so far. One user belongs to one company, and one company has many users.
The user table has a new column named company_id
The Company table has company_name
As for models:
User Model (... truncates unnecesary code)
class User < ActiveRecord::Base
...
belongs_to :company
accepts_nested_attributes_for :company
...
Company model:
class Company < ActiveRecord::Base
validates :company_name, presence: true, length: { maximum: 140}
has_many :employees, class_name: "User",
dependent: :destroy
end
As for Controllers:
The users controller create method looks like this:
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = I18n.t("controllers.users_controller.check_email")
redirect_to root_url
else
render 'new'
end
end
When user_params are:
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, company_attributes:[:company_name])
end
The companies controller is empty..
And the form for submitting is constructed like this:
<% #user.build_company %>
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label I18n.t("users.form.name") %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label I18n.t("users.form.email") %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.fields_for :company do |builder| %>
<%= builder.label I18n.t("users.form.company_name") %>
<%= builder.text_field :company_name, :class => "form-control" %>
<%end%>
<%= f.label I18n.t("users.form.password") %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label I18n.t("users.form.password_confirmation") %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>
I think that is all the information necessary I can think of, If you need anything else, please tell me.
Now I hit a brick wall, and not really sure how to move on from this place. Where and How should I implement something that checks if the input company name already exists, and if it does, give the users' column company_id the existing company id from the companies table, and otherwise just create the company and get him the new id.
Also, on a side note, did I understood good that the dependent: :destroy at company model will cause that if I delete a company from the database, all the users that belonged to the company will also be deleted?(at least that's what I wanted to achieve).
I will appreciate all the help!
Best regards,
Adam
Add :autosave. With this you can then use autosave_associated_records_for_company to determine how to save the child when parent is saved.
class User < ActiveRecord::Base
belongs_to :company, autosave: true
accepts_nested_attributes_for :company
def autosave_associated_records_for_company
if company
# Find or create the company by name
if new_company = Company.find_by_company_name(company.company_name)
self.company = new_company
else
self.company.save!
self.company_id = self.company.id
end
end
end
end
You can use before_save attributes for User model. Something like:
class User < ActiveRecord::Base
...
belongs_to :company
accepts_nested_attributes_for :company
before_save :find_or_created_by_company_name
...
def find_or_created_company
if Company.find(self.company_id).count == 0
# There is no company existed
self.company_id = Company.new()
... # Do whatever you want for your logical
end
end
About the dependent: :destroy: you are right. Reference here
I have been working on PHP. Presently trying to learn Ruby on Rails. I am learning Rails online, for now I am badly stuck on Sign-up or can say a form submission page. Sorry if it's too silly.
Error is:
undefined method new for nil:NilClass
Here is the code:
users_controller.rb
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user.new(params[:user])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
new.html.erb
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
<p> Username:</br> <%= f.text_field :username%> </p>
<p> Email:</br> <%= f.text_field :email%> </p>
<p> Password:</br> <%= f.password_field :password%></p>
<p> Password Confirmation:</br> <%= f.password_field :password_confirmation%> </p>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
user.rb
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true #:format => EMAIL_REGEX
validates :password, `enter code here`:presence =>true #:confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
end
In your users_controller > create, you put capital letter on User param.
For your case, it should be all lower case params[:user].
Side note, it actually depends on your attribute name you set on the form in the first place.
Edit:
In addition of that you should put #user = User.new(params[:user])
First thing you should create new object of User class
Second pass correct params key
change first line in create method to
#user = User.new(params[:user])
So the changed code will look like this:
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
change #user.new(params[:user]) to #user = User.new(params[:user]) I creates #user but it is not saved to database yet. On the line below #user.save that is when it gets saved. And remove render new because it will render the template with out setting the variables that the template needs. instead use redirect_to :new that will send the user to new and also set the variables needed
I guess you need to allow the params of User model in the User controller so as to avoid the forbidden error message as mentioned here. Please note that this is Rails feature as mentioned
Rails has several security features that help you write secure applications, and you're running into one of them now. This one is called strong parameters, which requires us to tell Rails exactly which parameters are allowed into our controller actions.
Thanks
I seem to be having a problem with receiving products through my join table, it's giving me a strange error as it seems to be receiving no ID for my order. I can only assume that this is because the order has not been created yet, but I am creating the order during this step anyway, so the order doesn't have an ID yet. So this is my problem.
Here is the error I recieve:
ActiveRecord::RecordNotFound in OrdersController#create
Couldn't find Product with ID=1 for Order with ID=
Rails.root: /BillingSystem
Application Trace | Framework Trace | Full Trace
app/controllers/orders_controller.rb:10:in `new'
app/controllers/orders_controller.rb:10:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jE2wdERoxE7PKwBhN60KAfguxwAq8qdW4wbru51SMFg=",
"order"=>{"client_id"=>"1",
"products_attributes"=>{"1368396234677"=>{"id"=>"1",
"_destroy"=>"false"}}},
"commit"=>"Create Order"}
Show session dump
Show env dump
Response
Headers:
None
New Order View:
<% if current_user %>
<div id="dashboard">
<div id="logo"></div>
<table id="go_back_link_container">
<tr>
<td>
<div class="go_back_link">
<%= link_to "<- Go Back", "/orders/view" %>
</div>
</td>
<td>
<div id="user_display">
Logged in as <%= current_user.email %>.
<%= link_to "Log out", log_out_path %>
</div>
</td>
</tr>
</table>
<%= form_for #order, method: :post do |f| %>
<% if #order.errors.any? %>
<div class="error_messages">
<% for message in #order.errors.full_messages %>
* <%= message %> <br>
<% end %>
</div>
<% end %>
<p>
<%= f.label 'Select The Client' %><br />
<%= select :order, :client_id, Client.all().collect { |c| [ (c.firstname + " " + c.surname), c.id ] } %>
</p>
<%= f.fields_for :products do |pf| %>
<% #render 'product_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Product", f, :products %>
<p class="button"><%= f.submit %></p>
<% end %>
<% flash.each do |name, msg| %>
<%= content_tag :div, "* " + msg, :id => "flash_#{name}" %><br />
<% end %>
<div id="copyright-notice"><div id="copyright_border">Copyright © Conner McCabe, all rights reserved.</div></div>
</div>
<% else %>
<script type="text/javascript">
window.location="<%= root_url %>"
</script>
<% end %>
Order Model:
class Order < ActiveRecord::Base
has_many :orderedproducts
has_many :products, through: :orderedproducts
has_one :client
attr_accessible :client_id, :order_total, :delivery_date, :products, :products_attributes
accepts_nested_attributes_for :products, :allow_destroy => true
before_save :generate_total
def generate_total
self.order_total = self.products.map(&:product_price).sum
end
end
Orders Controller:
class OrdersController < ApplicationController
def view
#orders = Order.all
end
def new
#order = Order.new
end
def create
#order = Order.new(params[:order])
if #order.save
redirect_to '/orders/view', :notice => "Order Created!"
else
render "new"
end
end
end
Product Fields Partial:
<fieldset>
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Products Model:
class Product < ActiveRecord::Base
#This line makes these elements accessible outside of the class.
attr_accessible :product_name, :product_price, :product_quantity, :product_supplier
has_many :orderedproducts
has_many :orders, through: :orderedproducts
#These attributes ensure that the data entered for each element is valid and present.
validates_presence_of :product_name
validates_presence_of :product_price
validates_numericality_of :product_price
validates_presence_of :product_quantity
validates_numericality_of :product_quantity
validates_presence_of :product_supplier
end
Application Helper:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
Ordered Products Model:
class Orderedproduct < ActiveRecord::Base
attr_accessible :order_id, :product_id, :quantity_ordered
belongs_to :order
belongs_to :product
end
I have listed every possible file that could contain an error, I know it's a bit excessive, but it's everything that is to do with it and better I include it than not at all.
I also followed this railscast guide: http://railscasts.com/episodes/196-nested-model-form-revised
To get to where I am, I edited it slightly so that it was suitable for my application.
Thanks in advance.
We had a similar issue on a project, except the relation was singular. The problem is that ActiveRecord is looking for an existing association; something like order.products.find(1). Since order is as new record this doesn't work.
You could create your own products_attributes= method and define the correct behaviour. But I think that you could just use nested attributes for the join model (Orderedproduct) instead of Product.
class Order
accepts_nested_attributes_for :orderedproducts
end
Then adjust the form fields appropriately. In the new form
f.fields_for :products do |pf| becomes f.fields_for :orderedproducts do |pf|
In the fields partial
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %> becomes <%= f.select :product_id, Product.all().collect {|p| [ p.product_name, p.id ] } %>
I am very new bee to ruby on rails, i have just created a small project which add,update and delete a record from mysql db
I am able to successfully add and delete record from mysql db from ruby application
But the issue is only when i try to update the existing record
My code is as follows,
Controller:
class BookController < ApplicationController
def list
#books = Book.find(:all)
end
def show
#book = Book.find(params[:id])
end
def new
#book = Book.new
#subjects = Subject.find(:all)
end
def create
#book = Book.new(params[:book])
if #book.save
redirect_to :action => 'list'
else
#subjects = Subject.find(:all)
render :action => 'new'
end
end
def edit
#book = Book.find(:all)
#subjects = Subject.find(:all)
end
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
redirect_to :action => 'show', :id => #book
else
#subjects = Subject.find(:all)
render :action => 'edit'
end
end
def delete
Book.find(params[:id]).destroy
redirect_to :action => 'list'
end
def show_subjects
#subject = Subject.find(params[:id])
end
end
List HTML:
<% if #books.blank? %>
<p>There are not any books currently in the system.</p>
<% else %>
<p>These are the current books in our system</p>
<ul id="books">
<% #books.each do |c| %>
<li>
<%= link_to c.title, {:action => 'show', :id => c.id} -%>
<b><%= link_to "edit", {:action => 'edit', :id => c.id} %></b>
<b> <%= link_to "Delete", {:action => 'delete', :id => c.id},
:confirm => "Are you sure you want to delete this item?" %></b>
</li>
<% end %>
</ul>
<% end %>
<p><%= link_to "Add new Book", {:action => 'new' }%></p>
Edit HTML:
=========
<h1>Edit Book Detail</h1>
<%= form_tag(:action=> "update") do%>
<p><label for="book_title">Title</label>:
<%= text_field 'book', 'title' %></p>
<p><label for="book_price">Price</label>:
<%= text_field 'book', 'price' %></p>
<p><label for="book_subject">Subject</label>:
<%= collection_select(:book, :subject_id,
#subjects, :id, :name) %></p>
<p><label for="book_description">Description</label><br/>
<%= text_area 'book', 'description' %></p>
<%= submit_tag "Save changes" %>
<%end %>
<%= link_to 'Back', {:action => 'list' } %>
I am getting the following exception when i try to edit a record from URL http://localhost:3000/book/edit/5,
Showing C:/app/app/views/book/edit.html where line #5 raised:
undefined method `title' for #<Array:0x33315c0>
Extracted source (around line #5):
2: <%= form_tag(:action=> "update") do%>
3:
4: <p><label for="book_title">Title</label>:
5: <%= text_field 'book', 'title' %></p>
6: <p><label for="book_price">Price</label>:
7: <%= text_field 'book', 'price' %></p>
8: <p><label for="book_subject">Subject</label>:
BTW i am using rails3,ruby1.2 and mysql5.5.
As i am in a learning curve, it will be very useful if some one can help me in this issue.
For some reason you're loading all the book records when the usual intention of the edit method is to edit one of them.
To fix this, you should define a before_filter hook that handles loading records:
class BookController < ApplicationController
# Set a handler for loading the book for most actions, except those
# where loading a single book is not relevant.
before_filter :load_book, :except => [ :index, :new, :create ]
def edit
#subjects = Subject.find(:all)
end
def update
# Call the update_attributes method that will throw an exception if
# an error occurs.
#book.update_attributes!(params[:book])
redirect_to :action => 'show', :id => #book
rescue ActiveRecord::RecordInvalid
# This exception is triggered if there was an error saving the record
# because of a validation problem.
# Trigger 'edit' action
edit
# Render as if on 'edit' page
render :action => 'edit'
end
protected
def load_book
#book = Book.find(params[:id])
end
end
As a note, any time you call either find(:all) or all on a model, you run the risk of using up all the system memory and crashing both your application and the server it's running on. Pagination is absolutely essential unless you can be certain the number of records is small.
Using a before_filter makes it a lot easier to consolidate your various redundant find calls into one place and can make error handling a lot simpler.
I have following structure:
class User < ActiveRecord::Base
has_many :Hobbies, :dependent => :destroy
accepts_nested_attributes_for :hobbies, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class Hobby < ActiveRecord::Base
belongs_to :User
end
In my Users_controller.rb
def index
#data = User.all(:joins => :hobbies)
end
In index.html.erb
<% for item in #data %>
<tr>
<td><%= item.id %></td> #from table Users
<td><%= item.hobby_name %></td> #from table Hobbies
</tr>
<% end %>
And this gives me an error undefined method `hobby_name' for # User:0x103cf7480>
I thought that I have that associations right, but this error makes confused... Can you help me someone, please, where could be a problem?
You must specify the relation, your object doesn't have an attribute called hobby_name, it has an association to multiple hobbies, and each hobby has an attribute called hobby_name
So:
<% item.hobbies.each do |h| %>
<%= h.hobby_name %>
<% end %>