I am making an online library system with Ruby on Rails. Currently users can sign up, but to do so they must first choose a type of subscription plan.
In the end, the best way I found to do this, was to pass a plan_id like so:
config/routes.rb
get 'subscribe/paperback2u', to: 'members#new', :plan_id => 1
get 'subscribe/paperback4u', to: 'members#new', :plan_id => 2
get 'subscribe/paperback6u', to: 'members#new', :plan_id => 3
Then, members/new.html.erb pulls the form partial, which looks like this:
<%= form_with(model: member, local: true) do |form| %>
<% plan_id = params[:plan_id] %>
<div class="field form-group">
<%= form.label :first_name, "First Name" %>
<%= form.text_field :first_name,
id: :member_first_name,
:class => "form-control",
:required => true %>
</div>
<div class="field form-group">
<%= form.label :last_name, "Last Name" %>
<%= form.text_field :last_name,
id: :member_last_name,
:class => "form-control",
:required => true %>
</div>
<div class="field form-group">
<%= form.label :address_line_1, "Address Line 1" %>
<%= form.text_field :address_line_1,
id: :member_address_line_1,
:class => "form-control",
:required => true %>
</div>
<div class="field form-group">
<%= form.label :address_line_2, "Address Line 2" %>
<%= form.text_field :address_line_2,
id: :member_address_line_2,
:class => "form-control" %>
</div>
<div class="field form-group">
<%= form.label :town %>
<%= form.text_field :town,
id: :member_town,
:class => "form-control",
:required => true %>
</div>
And the other fields for the member model.
Then we get to:
98 <%= form.hidden_field :plan_id, value: params[:plan_id] %>
100 <% if form.object.new_record? %>
101 <%= render 'stripe-form' %>
102 <% end %>
I don't think line 98 is doing anything, to be honest.
Then the stripe-form partial looks like this:
1 <div class="text-center">
2 <script src="https://checkout.stripe.com/checkout.js" class="stripe-button btn-primary"
3 data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
4 data-description="Subscribe to ReadAll Library"
5 data-amount=<%= (Plan.find(params["plan_id"].to_i).display_price) * 100 %>
6 data-currency="gbp"
7 data-panelLabel="Subscribe for"
8 data-label="Subscribe"
9 data-locale="auto"></script>
10 </div>
The error I am getting is:
Error:
MembersControllerTest#test_should_get_new:
ActionView::Template::Error: Couldn't find Plan with 'id'=1
app/views/members/_stripe-form.html.erb:5:in `_app_views_members__stripe_form_html_erb___374722773566915779_70180218242520'
app/views/members/_form.html.erb:101:in `block in _app_views_members__form_html_erb__2640496602018942691_70180179508500'
app/views/members/_form.html.erb:1:in `_app_views_members__form_html_erb__2640496602018942691_70180179508500'
app/views/members/new.html.erb:5:in `_app_views_members_new_html_erb___3025732295195500162_70180218177380'
test/controllers/members_controller_test.rb:16:in `block in <class:MembersControllerTest>'
The error I get if I add puts response.body in the tests is: "Plan must exist". Which it does! I have 3 different plans in my plans table. Each one has an ID, and everything works when I actually run it. It's just the test that doesn't work. I'd scrap the test if I could, but I need it as documentation for a project.
Finally, here's my Plan.rb and Member.rb
`plan.rb`
class Plan < ApplicationRecord
has_many :members
end
`member.rb`
class Member < User
1 require 'stripe'
2
3 before_save :set_type
4
5 belongs_to :plan
6
7
8 def set_type
9 self.type = "Member"
10 end
11
12 end
And the schema for the two:
create_table "plans", force: :cascade do |t|
t.string "stripe_id"
t.string "nickname"
t.decimal "display_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "product"
end
create_table "users", force: :cascade do |t|
bunch of user attributes (first_name, address, etc)
t.string "type" (members is a users type)
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "remember_digest"
t.string "customer_id"
t.bigint "plan_id"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["plan_id"], name: "index_users_on_plan_id"
end
I'm out of ideas. I appreciate any help you guys can give me. Cheers.
In your view, if you want that your user choose from the form, you could add the select input and let the user select what plan they want. But it's all possible that you pass this information through URL, as you already did.
View:
<%= form_with(model: member, local: true) do |form| %>
<div class="field form-group">
<%= form.label :first_name, "First Name" %>
<%= form.text_field :first_name,
id: :member_first_name,
:class => "form-control",
:required => true %>
</div>
<div class="field form-group">
<%= form.label :plan, "Choose your plan" %>
<%= form.select :plan_id,
Plan.all {|p| [ p.name, p.id ]},
{ include_blank: false, selected: form.object.plan_id }, class: 'form-control' %>
</div>
<%= f.submit "Salvar", class: "btn btn-primary" %>
<% end %>
I believe the rest you already did it. In the controller you add to the white list of params the plan_id, and in your model you add model relations as has_many and belong. P.s: I didn't test this.
Related
I am trying to do the seemingly innocuous task of passing an array of tags to a new subscriber form, based on which page it's rendered on.
My Subscriber table looks like this in schema.rb:
create_table "subscribers", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "phone"
t.string "email"
t.text "tags", default: [], array: true
t.text "admin_notes"
t.boolean "unsubscribe"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
My partial is rendered like this:
<%= render partial: "layouts/new_subscriber", locals: { tags: "buyer, LM-house-tour-checklist" } %>
Which brings up this _new_subscriber.html.erb partial:
<%= simple_form_for(#new_subscriber) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.label :first_name %>
<%= f.text_field :first_name, required: true, class: "form-control" %>
<%= f.label :last_name %>
<%= f.text_field :last_name, required: true, class: "form-control" %>
<%= f.label :phone %>
<%= f.text_field :phone, required: true, class: "form-control" %>
<%= f.label :email %>
<%= f.text_field :email, required: true, class: "form-control" %>
<%= f.hidden_field :tags, value: tags %>
</div>
<div class="form-actions text-center">
<%= f.submit "Get My Checklist", class: "btn" %>
</div>
<% end %>
I have tested using the Chrome code inspector that "buyer, LM-house-tour-checklist" is getting passed into the hidden field value.
However, when I submit, it creates the subscriber with a :tags attribute of ["uyer"]. This is super weird and unexplainable to me.
Some other info:
There is nothing in my subscriber model.
#new_subscriber is defined in my ApplicationController using before_action :new_subscriber and def new_subscriber #new_subscriber = Subscriber.new end
I have tried the method described here, but to no avail
Can anyone help me do this in the "Railsiest" way possible? It dosn't seem like that unusual of an ask, but I can't get it to work properly.
Maybe because it's sent as string.
Try to add attr_accessor :plain_tags in model
Instead of tags field use this attribute.
And in before_create callback write something like
before_create :populate_tags
def populate_tags
return if self.tags_plain.blank?
self.tags = self.tags_plain.split(",")
end
Trace: https://i.gyazo.com/6487f4eee162e8c2207d7fdb5fc4ef3b.png
I can't get what's happening, I did the same process with the contact page and everything worked fine. Any ideas?
profile/new.html.erb
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1 class="text-center">Create Your Profile</h1>
<p class="text-center">Be a part of the DevMatch community and fill out your profile!</p>
<div class="well">
<%= render 'form' %>
</div>
</div>
</div>
profile/_form.html.erb
<%= form_for #profile, url: user_profile_path do |f| %>
<div class="form-group">
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :last_name %>
<%= f.text_field :last_name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :job_title %>
<%= f.select :job_title, ['Developer', 'Entrepreneur', 'Investor'], {}, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :phone_number %>
<%= f.text_field :phone_number, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :contact_email %>
<%= f.text_field :contact_email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.submit "Update Profile", class: 'btn btn-primary' %>
</div>
<% end %>
schema
create_table "profiles", force: :cascade do |t|
t.integer "user_id"
t.string "first_name"
t.string "last_name"
t.string "job_title"
t.string "phone_number"
t.string "contact_email"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Profiles controller
class ProfilesController < ApplicationController
# GET to /users/:user_id/profile/new
def new
# Render blank profile details form
#profile = Profile.new
end
end
I get the rror in the profile creator page. It says the firstname is undefined but I tried deleting it and then it says that the laast name is undefined and so on
If I delete the "<%= render 'form' %>" form the other html, the page loads perfectly, but I need a form and I am trying to learn Ruby. Sorry
undefined method `first_name' for Profile id: nil
It says the firstname is undefined but I tried deleting it and then it
says that the last name is undefined and so on
You didn't have columns in the profiles table. You should run rake db:migrate to migrate the columns which should resolve your problem.
Additionally always make sure your migrations are run properly without any errors You check the status of the pending migrations with rake db:migrate:status
I've been trying Ruby on Rails for a few months now, re-engineering a desktop application. This application has a form for updating take-off and landing points, whose coordinates must be confirmed. Well, I tried validates_confirmation_of method however it works only with String attributes, and I have Integer and Decimal types. Hence I created an alternative method by borrowing an excerpt from the helper (confirmation.rb), which is working fine. But I wonder if there is another way to do it or whether this solution can be improved. Below follows a compact version of the source files. Thanks in advance!
Migration:
class CreateWaypoints < ActiveRecord::Migration[5.0]
def change
create_table :waypoints do |t|
t.string :name
t.integer :latitude_in_degrees
t.integer :latitude_in_minutes
t.decimal :latitude_in_seconds, precision: 5, scale: 2
t.timestamps
end
add_index :waypoints, [:name], unique: true
end
end
View:
<%= simple_form_for(#waypoint) do |f| %>
<%= f.error_notification %>
<div class="form-inline">
<%= f.input :name %>
</div>
<div class="form-inline">
<%= f.input :latitude_in_degrees %>
<%= f.input :latitude_in_minutes %>
<%= f.input :latitude_in_seconds %>
</div>
<div class="form-inline">
<%= f.input :latitude_in_degrees_confirmation, as: :numeric, label: false %>
<%= f.input :latitude_in_minutes_confirmation, as: :numeric, label: false %>
<%= f.input :latitude_in_seconds_confirmation, as: :numeric, label: false %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Model:
class Waypoint < ApplicationRecord
...
validates_each :latitude_in_degrees, :latitude_in_minutes, :latitude_in_seconds do |record, attribute, value|
if record.send("#{attribute}_changed?")
confirmed = record.send("#{attribute}_confirmation")
if confirmed.to_s != value.to_s
human_attribute_name = record.class.human_attribute_name(attribute)
record.errors.add(:"#{attribute}_confirmation", "Doesn't match #{human_attribute_name}")
end
end
end
end
I have created a valuation table which contain
class CreateValuations < ActiveRecord::Migration
def change
create_table :valuations do |t|
t.text :location
t.integer :number_of_bedroom
t.integer :number_of_bath
t.integer :age_of_building
t.text :other_details
t.string :name
t.string :email
t.integer :contact_number
t.timestamps null: false
end
end
end
And later i added a column :building of type text in it using rails generate migration add_building_to_valuations building:text. I have created a form
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#valuation) do |val| %>
<%= val.label :building, "Name of Building/Builder" %>
<%= val.text_field :building, class: 'form-control' %>
<%= val.label :location, "Location" %>
<%= val.text_field :location, class: 'form-control' %>
<%= val.label :number_of_bedroom, "Number of Bedroom" %>
<%= val.text_field :number_of_bedroom, class: 'form-control' %>
<%= val.label :number_of_washroom, "Number of Washroom" %>
<%= val.text_field :number_of_bath, class: 'form-control' %>
<%= val.label :age_of_building, "Age of Building" %>
<%= val.text_field :age_of_building, class: 'form-control' %>
<%= val.label :name, "Name" %>
<%= val.text_field :name, class: 'form-control' %>
<%= val.label :email, "Email" %>
<%= val.text_field :email, class: 'form-control' %>
<%= val.label :contact_number, "Contact Number" %>
<%= val.text_field :contact_number, class: 'form-control' %>
<%= val.submit "Evaluate my property", class: "btn btn-primary" %>
<% end %>
</div>
</div>
When i fill all the field and submit via Evaluate my property, Then no data is being saved in :building.
I checked this using following commands
$ rails console
$ Valuation.all
and received output are following output
#<Valuation id: 1, location: "Chandivali, Powai",
number_of_bedroom: 3, number_of_bath: 3,
age_of_building: 9, other_details: nil, name: "Shravan",
email: "shravan.xxx#gmail.com",
contact_number: "9876543210",created_at: "2015-11-14 09:47:26",
updated_at: "2015-11-14 09:47:26", building: nil>,
You should update your valuation_params Which is most likely a private function
private
def valuation_params
params.require(:valuation).permit(:building,
:location,
:number_of_bedroom,
:number_of_bath,
:age_of_building,
:name, :email, :contact_number)
end
end
I am working on an app where people can go to edit their user and upon submission it redirects them to their show profile view.
This all seems to work according to plan but for some reason some when I go back to my edit view I see that some of my form fields get automatically pre-populated while others don't.
Why is this happening?
Specifically the all text fields are being remembered and pre-populated but my image file field and time weekly fields are not. They are definitely still in the database and are displayed in my show view but not pre-populated on the edit view?
Do certain types of fields not get pre-populated or what is this behavior? I would ideally like to have all of the fields pre-populated(image, dates, text, etc)
Here is my code:
Edit view:
<div class="editprofilebox">
<h1>Take a moment to fill out your profile:</h1>
<div class="container-fluid">
<div class="edit-profile-form">
<%= form_for #user, :html => { :role => 'form', :class => 'form-horizontal', :multipart => true } do |f| %>
<div class="form-inputs">
<div class="row">
<div class= "col-sm-4">
<div class: "form-group">
<%= f.text_field :first_name, class: "form-control", placeholder:"First Name" %>
</div>
<div class: "form-group">
<%= f.text_field :last_name, class: "form-control", placeholder:"Last Name" %>
</div>
<div class: "form-group">
<%= f.label :profile_image, class: "control-label" %>
<%= f.file_field :image, class: "profile-picture-upload" %>
</div>
</div>
<div class= "col-sm-4">
<div class: "form-group">
<%= f.label :twitter %>
<%= f.text_field :twitter, class: "form-control", placeholder:"Type your update title here" %>
</div>
<div class: "form-group">
<%= f.text_field :occupation, class: "form-control", placeholder:"Occupation" %>
</div>
<div class: "form-group">
<%= f.text_field :gender, class: "form-control", placeholder:"Gender" %>
</div>
<div class: "form-group">
<%= f.text_field :work_history, class: "form-control", placeholder:"Work History" %>
</div>
<div class: "form-group">
<%= f.number_field :years_of_experience, class: "form-control", placeholder:"years_of_experience" %>
</div>
</div>
<h3> time available </h3>
<div class="col-sm-2">
<%= f.label :Monday %>
<%= f.check_box :monday, class: "time-checkbox", placeholder:"Type your update title here" %>
<%= f.time_field :mondaytime1, class: "form-control time-box"%>
<%= f.time_field :mondaytime2, class: "form-control time-box" %>
<%= f.label :Tuesday %>
<%= f.check_box :tuesday, class: "time-checkbox", placeholder:"Type your update title here" %>
<%= f.time_field :tuesdaytime1, class: "form-control time-box" %>
<%= f.time_field :tuesdaytime2, class: "form-control time-box" %>
<%= f.label :Wednesday %>
<%= f.check_box :wednesday, class: "time-checkbox" %>
<%= f.time_field :wednesdaytime1, class: "form-control time-box" %>
<%= f.time_field :wednesdaytime2, class: "form-control time-box" %>
<%= f.label :Thursday %>
<%= f.check_box :thursday, class: "time-checkbox" %>
<%= f.time_field :thursdaytime1, class: "form-control time-box" %>
<%= f.time_field :thursdaytime2, class: "form-control time-box" %>
</div>
<div class:"col-sm-2">
<%= f.label :Friday %>
<%= f.check_box :friday, class: "time-checkbox" %>
<%= f.time_field :fridaytime1, class: "form-control time-box" %>
<%= f.time_field :fridaytime2, class: "form-control time-box" %>
<%= f.label :Saturday %>
<%= f.check_box :saturday, class: "time-checkbox" %>
<%= f.time_field :saturdaytime1, class: "form-control time-box" %>
<%= f.time_field :saturdaytime2, class: "form-control time-box" %>
<%= f.label :Sunday %>
<%= f.check_box :sunday, class: "time-checkbox" %>
<%= f.time_field :sundaytime1, class: "form-control time-box" %>
<%= f.time_field :sundaytime2, class: "form-control time-box" %>
</div>
</div>
</div>
<div class="form-actions">
<%= f.button :submit, class: "btn btn-default btn-lg" %>
</div>
<% end %>
</div>
</div>
</div>
show view:
<div class="profilebox">
<div class="profile-title-box" >
<%= #user.first_name %> <%= #user.last_name %> profile
</div>
<hr>
<div class="profile-container">
<div class="row ">
<div class="profile-image-box col-sm-4" >
<%= image_tag #user.image.thumb('150x185#').url if #user.image_stored? %>
</div>
<div class="profile-info-box col-sm-8">
<%= #user.email %>
</br>
<%= #user.first_name %>
</br>
<%= #user.last_name %>
</br>
<%= #user.occupation %>
</br>
<%= #user.gender %>
</br>
<%= #user.work_history %>
</br>
<%= #user.years_of_experience %>
</br>
</div>
</div>
</div>
<hr>
<div class="profile-extra-box">
<h3>Complete your profile here:</h3>
<%= link_to 'Edit', edit_user_path(#user) %>
</div>
</div>
users controller:
class UsersController < ApplicationController
def new
end
def show
#user = User.find(params[:id])
end
def index
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find_by_id(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "User updated successfully!"
redirect_to user_path
else
flash[:danger] = "User could not be updated!"
end
end
def destroy
end
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :image, :twitter, :monday, :mondaytime1, :mondaytime2, :tuesday, :tuesdaytime1, :tuesdaytime2, :wednesday, :wednesdaytime1, :wednesdaytime2, :thursday, :thursdaytime1, :thursdaytime2, :friday, :fridaytime1, :fridaytime2, :saturday, :saturdaytime1, :saturdaytime2, :sunday, :sundaytime1, :sundaytime2, :occupation, :gender, :years_of_experience, :work_history)
end
end
Scheema:
ActiveRecord::Schema.define(version: 20140906225655) do
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name"
t.string "last_name"
t.string "image_uid"
t.string "image_name"
t.text "twitter"
t.boolean "monday"
t.text "mondaytime1"
t.text "mondaytime2"
t.boolean "tuesday"
t.text "tuesdaytime1"
t.text "tuesdaytime2"
t.boolean "wednesday"
t.text "wednesdaytime1"
t.text "wednesdaytime2"
t.boolean "thursday"
t.text "thursdaytime1"
t.text "thursdaytime2"
t.boolean "friday"
t.text "fridaytime1"
t.text "fridaytime2"
t.boolean "saturday"
t.text "saturdaytime1"
t.text "saturdaytime2"
t.boolean "sunday"
t.text "sundaytime1"
t.text "sundaytime2"
t.string "occupation"
t.string "gender"
t.string "work_history"
t.decimal "years_of_experience"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
"Pre-population" has two connotations, both of which you need to consider:
Browser-based data
Server-based data
Browser
The difference here is that browser based data is basically the "remember me" stuff you type into forms on e-commerce sites and the like.
The reason I mention this is because when you have a user form, modern browsers (exclusing IE) will generally populate it with the relevant data you have used before. This can be seen with this introduction to Autofill on Chrome's site:
In essence, it means that if you load standard "input names" on your pages, Chrome will endeavour to populate them with data you've either saved, or inputted into other websites.
Firstly, you need to make sure you are not having your details inputted by the browser. If this the is the case, it will mean you've got to get the server-side functionality working regardless.
Either way, you should look at using the server-based data as described below:
Server
Secondly, you'll have sever-based data. This is real Rails data, and what you need in your page:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def edit
#user = User.find params[:id]
end
end
#app/views/users/edit.html.erb
<%= form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= image_tag #user.image.url if #user.image.present? %>
<%= f.file_field :image %>
<%= f.submit %>
<% end %>
As per the form_for documentation, if you have the correct ActiveRecord object populated, and have the data in your database, calling the attribute-based input helpers should populate for you.
There are some caveats to this, however:
--
Image
Using file_field will not pre-populate your image.
The file upload element is distinctly different to the image element - simply that the upload element cannot show you an image. This means you have to explicitly show the image in your edit form, if indeed you want to show it:
# Edit View
<%= image_tag #user.image.thumb('150x185#').url if #user.image_stored? %>
<%= f.file_field :image %>
We've used this method here (just sign up for free and try to upload a profile image):
Although we used JQuery heavily here, we made it so that the image form shows the image, which then gives you the ability to upload a new one.
--
Time
Frankly, I'm not sure about your time field.
Like the explanation above, you'll want to ensure you're using the attributes from your database to populate your time fields. I see you're using a lot of different checkboxes, which although might help create a better system, will likely not populate the data you want