I have someone of a unique problem. I have 3 tables in the database that I need to populate with data. All tables are in relation to each other. The first table's info will be static and populated from a hash. The second table is the table that is usually targeted with data.
I am having a tough time trying to add data into the second table using strong parameters. I get an error param is missing or the value is empty: entries
Modles:
client.rb
class Client < ActiveRecord::Base
has_many :entries
end
Entry.rb
class Entry < ActiveRecord::Base
belongs_to :client_name
has_many :extra_data
end
extra_data.rb
class ExtraData < ActiveRecord::Base
belongs_to :entries
end
class ClientsController < ApplicationController
before_action :set_client, only: [:show, :update, :destroy, :edit]
# submit for all intended purposes.
#
def new
#entries = Entry.new()
end
def create
#client = Client.new(CLEINT_ATTR)
if #client.save
#entries = Entry.new(submit_params)
redirect_to action: :index
else
flash.alert "you failed at life for today."
redirect_to action: :index
end
end
.
.
.
private
def submit_params
params.require(:entries).permit( :full_name,:email,:opt_in )
end
def set_client
#client = Client.find(params[:id])
end
end
form
<%= simple_form_for(:client, url: {:controller => 'clients', :action => 'create'}) do |f| %>
<%= f.input :full_name %>
<%= f.input :email %>
<%= f.input :opt_in %>
<%= f.button :submit, class: "btn-primary" %>
<% end %>
Routes:
Rails.application.routes.draw do
resources :clients do
resources :entries do
resources :extra_data
end
end
root 'clients#index'
end
In the Database Client data goes in with out a problem. I am having a problem getting the data from the form itself.
This answer is the culmination of a few different parts.
I figured out I was not saving any data into the model. So I needed to make another if statement.
def create
#client = Client.new(CLEINT_ATTR)
if #client.save
#entries = Entry.new(submit_params)
if #entries.save
flash[:alert] = "Failure! everything is working."
redirect_to action: :index
else
flash[:alert] = "Success! at failing."
end
else
flash[:alert] = "you failed at life for today."
redirect_to action: :thanks
end
end
Also changing the form from :entries Helped. I also had a typo in my permit statment. I had :opt_in when I needed to use :optin Thanks #tmc
Related
I'm making simple CRUD and the current goal is to add data. However, I found that I can't add any data, and the terminal log also shows "[Webpacker] Everything's up-to-date. Nothing to do", which means there is no error message.
According to my design in the controller, the new data must have failed, so I stopped at new.html.erb. I'm guessing it has something to do with the model's relationship.
This is model User
class User < ApplicationRecord
has_many :reviews
has_many :recipes, through: :reviews
end
This is the model Recipe
class Recipe < ApplicationRecord
has_many :reviews
belongs_to :user
end
This is model Review
class Review < ApplicationRecord
belongs_to :user
belongs_to :recipe
end
This is the RecipeController
class RecipesController < ApplicationController
def index
#recipes = Recipe.all
end
def new
#recipe = Recipe.new
end
def create
#recipe = Recipe.new(recipe_params)
if #recipe.save
redirect_to recipes_path, notice: "Successful!"
else
render :new
end
end
private
def recipe_params
params.require(:recipe).permit(:title, :money)
end
end
this is the web page
<h1>Add New One</h1>
<%= form_for(#recipe) do |r| %>
<%= r.label :title, "Title" %>
<%= r.text_field :title%>
<%= r.label :money, "Budget" %>
<%= r.text_field :money %>
<%= r.submit %>
<% end %>
<%= link_to "Back to list", recipes_path %>
You should first add a callback to ensure that only signed in users can create recipes (unless you actually want to let anomynous users create/update/delete recipies).
For example with Devise you would use its authenticate_user! helper which will bail and redirect to the sign in path if the user is not authenticated:
class RecipesController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
# ...
end
If you're reinventing the authentication wheel you should create a similiar method which is used to prevent access.
You would then initialize the resource off the current user:
class RecipesController < ApplicationController
before_action :authenticate_user!, except: [:show, :index]
def create
#recipe = current_user.recipes.new(recipe_params)
if #recipe.save
redirect_to recipes_path, notice: "Successful!"
else
render :new
end
end
end
Here I am assuming that you have a current_user method which will retrieve the user based on an id stored the session.
Since you have an indirect assocation this will create a row in the reviews table with the users id and the recipe id as the record in the recipies table.
You also want to display the validation errors in the form so that the user gets feedback.
You are probably right that it is a validation error related to the belongs_to relationship. You should display validation errors for your form as described here https://guides.rubyonrails.org/getting_started.html#validations-and-displaying-error-messages
I've spent a while trying to debug this behavior unsuccessfully, so I'm hoping for help figuring out why my nested resource parameters appear to be getting included in the URL in the wrong order. For some reason, adding and deleting lessons for a course works, but editing a lesson crashes because ActiveRecord tries to find a lesson using the course ID and vice versa.
Course and lesson models
class Course < ApplicationRecord
has_many :lessons, dependent: :destroy
extend FriendlyId
friendly_id :title, use: :slugged
class Lesson < ApplicationRecord
belongs_to :course
extend FriendlyId
friendly_id :title, use: :slugged
Lessons controller
class LessonsController < ApplicationController
before_action :set_lesson, only: [:show, :edit, :update, :destroy ]
def index
#lessons = Lesson.all
end
def show
end
def new
#lesson = Lesson.new
#course = Course.friendly.find(params[:course_id])
authorize #lesson
end
def edit
authorize #lesson
end
def create
#lesson = Lesson.new(lesson_params)
#course = Course.friendly.find(params[:course_id])
#lesson.course_id = #course.id
if #lesson.save
redirect_to course_lesson_path(#course, #lesson), notice: "Lesson was successfully created."
else
render :new, status: :unprocessable_entity
end
end
def update
authorize #lesson
if #lesson.update(lesson_params)
redirect_to course_lesson_path(#course, #lesson), notice: "Lesson was successfully updated."
else
render :edit
end
end
def destroy
authorize #lesson
#lesson.destroy
redirect_to course_path(#course), notice: "Lesson was successfully destroyed."
end
private
def set_lesson
#course = Course.friendly.find(params[:course_id])
#lesson = Lesson.friendly.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :content, :course_id)
end
end
Routes
resources :courses do
resources :lessons
end
And what shows up when I do rails routes:
edit_course_lesson GET /courses/:course_id/lessons/:id/edit(.:format)
However, when I actually edit a lesson, the parameters seem to get switched, which causes a crash. See below for an example of where it thinks the fourth lesson is the course.
URL: /courses/fourth-lesson/lessons/forensic-science-344/edit
ActiveRecord::RecordNotFound in LessonsController#edit
can't find record with friendly id: "fourth-lesson"
private
def set_lesson
#course = Course.friendly.find(params[:course_id]) <- Crashes on this line
#lesson = Lesson.friendly.find(params[:id])
end
Update: here's the form for editing a lesson.
.container
= simple_form_for([#course, #lesson]) do |f|
= f.error_notification
= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
.form-inputs
= f.input :title
= f.input :content
%small
= f.error :content, class: 'text-danger'
.form-actions
= f.button :submit, class: 'btn btn-primary my-4'
It turns out that I didn't pass in the course parameter on the edit link. I had link_to 'Edit', edit_course_lesson_path(lesson).
It should have been edit_course_lesson_path(#course, lesson).
Thanks for everyone's patience, and many thanks to Deepesh for finally getting it into my head to look at the edit link.
I've been banging my head against this one for few days now ......
my routes.rb file looks like this:
resources :vehicles do
member do
resources :services
end
end
my service.rb file shows:
class Service < ActiveRecord::Base
belongs_to :vehicle
end
my vehicle.rb file shows:
class Vehicle < ActiveRecord::Base
has_many :services, :dependent => :destroy
end
Here is services_controller.rb
class ServicesController < ApplicationController
def index
#vehicle = Vehicle.find(params[:id])
#services = #vehicle.services.order('created_at DESC')
end
def show
#vehicle = Vehicle.find(params[:id])
#service = Vehicle.services.find(params[:service_id])
end
def new
#vehicle = Vehicle.find(params[:id])
#service = #vehicle.services.new
end
def create
#vehicle = Vehicle.find(params[:id])
#service = #vehicle.services.build(service_params)
if #service.save
redirect_to #vehicle
else
render :new
end
end
private
def service_params
params.require(:service).permit(:service_option, :odometer,
:current_service, :price, :comments, :next_service)
end
end
And here is the services#index
<h1>Services</h1>
<% #services.each do |s| %>
<%= link_to "Details", service_path(s) %>
<%= s.created_at %>
<%= s.service_option %>
<%= s.odometer %><br>
<% end %>
Clicking on the "Details" link or manually entering the URL
http://localhost:3000/vehicles/2/services/7
gives my systematically the same routing error:
ActiveRecord::RecordNotFound in ServicesController#show
Couldn't find Vehicle with 'id'=7
Extracted source (around line #10):
def show
#vehicle = Vehicle.find(params[:id])
#service = Vehicle.services.find(params[:service_id])
end
It passes a SERVICE ID to a vehicle objet / variable and I don't know why!
Thanks a million!
In your services#show method you are fetching the vehicle and service with wrong params. Also Vehicle.services is wrong, it should be #vehicle.services
def show
#vehicle = Vehicle.find(params[:vehicle_id])
#service = #vehicle.services.find(params[:id])
end
Update:
You should remove member in the routes, else it will produce the routes like
service GET /vehicles/:id/services/:id(.:format) services#show
which are irrelevant
resources :vehicles do
resources :services
end
So now you will have routes like
service GET /vehicles/:vehicle_id/services/:id(.:format) services#show
which are relevant and you can fetch the vehicle with params[:vehicle_id] and service with params[:id]
Don't forget to change the route helpers. For instance service_path will become vehicle_service_path
<%= link_to "Details", vehicle_service_path(#vehicle,s) %>
Im new to rails and am having difficulty creating a profile by a devise user
here is the ProfileController:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#profiles = Profile.all
end
def new
#profile = current_user.build_profile
end
def create
#profile = current_user.build_profiles(profile_params)
redirect_to profiles_path
end
def show
end
def edit
end
def update
#profile.update(profile_params)
redirect_to(profiles_path(#profile))
end
def destroy
#profile.destroy
redirect_to profiles_path
end
private
def profile_params
params.require(:profile).permit(:university, :degree)
end
def set_profile
#profile = Profile.find(params[:id])
end
end
When i run the rails server i can submit the form but nothing is getting stored in the model 'Profile'
here is the index.html.erb where the data should appear:
<h2>profiles</h2>
<% #profiles.each do |profile| %>
<%= link_to profile do %>
<%= profile.university %>
<% end %>
<%= profile.degree %>
<% end %>
user.rb file:
has_one :profile
and the profile.rb file:
belongs_to :user
nothing seems to be getting saved to the profile model and nothing is getting displayed on the index.html.erb. Also i have created a migration to store user_id in the profile model.
Thank for your help
By far the best way to create a profile for a user is to build it when the User object is created:
#app/models/user.rb
class User < ActiveRecord::Base
has_one :profile
before_create :build_profile
accepts_nested_attributes_for :profile
end
#app/models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end
This will build a blank profile each time a new user is created. It means that each user will only ever have one profile, which they'll be able to populate & edit.
In regards your issue, there are several points:
Don't list "profiles" with an index, list users & pull their profile data
If managing a profile, nest it under the associative user model
Here's how to do that:
# config/routes.rb
resources :users, only: :index
resource :profile, only: [:show, :update]
#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
def show
end
def update
redirect_to :show if current_user.update profile_params
end
private
def profile_params
params.require(:user).permit(profile_attributes: [:name])
end
end
#app/views/profiles/show.html.erb
<%= form_for current_user, url: profile_path do |f| %>
<%= f.fields_for :profile do |p| %>
<%= p.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
Update
My post above is exactly what we do.
The way it works is very simple -- when a User is created (IE they have gone to the trouble of filling out their details), the Rails backend automatically creates a blank Profile object.
This does several things:
Always makes sure you have a Profile for each user (you don't have to go to the bother of making them "create" a profile).
Gives you the ability to validate only inputted data on a created Profile (not having to guess whether it's already been done).
--
If you're getting undefined method build_profile, it means your associations are incorrect.
All singular associations have build_[association] as defined instance methods. The code I provided fires build_profile for a has_one association. The only time it would be "undefined" would be if the association was plural
--
Update
This suggests a routing error.
Considering it appears at root, I think the problem is here:
#app/views/layouts/application.html.erb
<%= link_to "Profile", profile_path %>
You don't have edit_profile_path -- it should just be profile_path
It needs a save call for the profile which you build in crate method.
e.g.
def create
#user = User.new(user_params)
if #user.save
redirect_to root_url
else
render :new
end
end
if condition checks is data save correct or not. And change example's User model to your Profile model
BTW, just careful with the plural, I think it should use 'build_profile' instead 'build_profiles'
I'm developing a Ruby on Rails app and I'm trying to organize my code a bit better. Part of the app is a knowledgebase which is organized into categories and articles - pretty standard stuff.
Here is the way I have everything set up (at least what I think is important):
routes.rb
namespace :knowledgebase do
resources :categories
resources :articles
end
models/knowledgebase/article.rb
class Knowledgebase::Article < ActiveRecord::Base
self.table_name = 'knowledgebase_articles'
belongs_to :category, class_name: 'Knowledgebase::Category', foreign_key: 'knowledgebase_category_id'
end
models/knowledgebase/category.rb
class Knowledgebase::Category < ActiveRecord::Base
self.table_name = 'knowledgebase_categories'
has_many :articles, class_name: 'Knowledgebase::Article'
end
controllers/knowledgebase/articles_controller.rb
class Knowledgebase::CategoriesController < ApplicationController
load_and_authorize_resource
before_action :authenticate_user!
before_action :set_category, only: [:show, :edit, :update, :destroy]
def new
#category = ::Knowledgebase::Category.new
end
def create
#category = ::Knowledgebase::Category.new(category_params)
if #category.save
redirect_to knowledgebase_categories_url, notice: '...'
else
render :new
end
end
# ...
private
def set_category
#category = ::Knowledgebase::Category.find(params[:id])
end
def category_params
params.require(:category).permit(:title)
end
end
views/knowledgebase/categories/_form.html.erb
<%= form_for #category do |form| %>
<%= form.text_field :title
<%= form.submit %>
<% end %>
My Problem: when I try to submit the form (either new or edit) I get the error:
param is missing or the value is empty: category
When I setup the form like this: <%= form_for ([:knowledgebase, #category]) do |form| %> I get the following error:
undefined method `knowledgebase_knowledgebase_categories_path' for #<#<Class:0x007fecd7a78908>:0x007fecd707ad20>
The same goes for articles. I'm using Rails 4.2.3.
If anybody could help me or guide me into the right direction I would be really thankful - I have googled for three days now I tried everything I could think of.
Update 1
This is the params log generated:
{"utf8"=>"✓",
"authenticity_token"=>"fjOs...VA==",
"commit"=>"Category erstellen",
"knowledgebase_category"=>{"title"=>"Test Title"}}
As you look into the params hash, it has knowledgebase_category not category. So try changing category_params to the below
def category_params
params.require(:knowledgebase_category).permit(:title)
end
An Advice:
Always look into the generated params in the log. It really helps a lot in finding the solution to most of the errors.